diff mbox

[ovs-dev,v2,07/12] userspace: Add OXM field MFF_PACKET_TYPE

Message ID AM2PR07MB1042BCA89E7A4FB6FF029A118AC40@AM2PR07MB1042.eurprd07.prod.outlook.com
State Superseded
Headers show

Commit Message

Zoltan Balogh June 19, 2017, 4:11 p.m. UTC
Hi Ben,

I've been testing L2/L3 tunneling and ptap ports receiving/transmitting L2 and L3 packets. 
I observed, that 'ovs-appctl dpctl/dump-flows' prints out packet_type 'id' in decimal format.
For instance, in case of receiving a L3 MPLS packet on a ptap port results in:

tunnel(src=20.0.0.1,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(7),packet_type(ns=1,id=34887),eth_type(0x8847), packets:24, bytes:2112, used:0.064s, actions:drop

Would not it be more readable, to use hex format if the 'id' is not zero?

By applying this diff:


... we can get printouts like this:

recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:9
tunnel(src=20.0.0.1,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(7),packet_type(ns=1,id=0x8847),eth_type(0x8847), packets:0, bytes:0, used:never, actions:drop

Best regards,
Zoltan

> -----Original Message-----
> From: ovs-dev-bounces@openvswitch.org [mailto:ovs-dev-bounces@openvswitch.org] On Behalf Of Ben Pfaff
> Sent: Monday, June 19, 2017 1:30 AM
> To: dev@openvswitch.org
> Cc: Ben Pfaff <blp@ovn.org>
> Subject: [ovs-dev] [PATCH v2 07/12] userspace: Add OXM field MFF_PACKET_TYPE
> 
> From: Jan Scheurich <jan.scheurich@ericsson.com>
> 
> Allow packet type namespace OFPHTN_ETHERTYPE as alternative pre-requisite
> for matching L3 protocols (MPLS, IP, IPv6, ARP etc).
> 
> Change the meta-flow definition of packet_type field to use the new
> custom format MFS_PACKET_TYPE representing "(NS,NS_TYPE)".
> 
> Parsing routine for MFS_PACKET_TYPE added to meta-flow.c. Formatting
> routine for field packet_type extracted from match_format() and moved to
> flow.c to be used from meta-flow.c for formatting MFS_PACKET_TYPE.
> 
> Updated the ovs-fields man page source meta-flow.xml with documentation
> for packet-type-aware bridges and added documentation for field packet_type.
> 
> Added packet_type to the matching properties in tests/ofproto.at. Should be
> removed later, when packet_type_aware bridge attribute will be introduced.
> 
> Signed-off-by: Jan Scheurich <jan.scheurich@ericsson.com>
> Signed-off-by: Ben Pfaff <blp@ovn.org>
> ---
>  build-aux/extract-ofp-fields    |   3 +-
>  include/openvswitch/match.h     |   5 +
>  include/openvswitch/meta-flow.h |  20 ++++
>  lib/flow.c                      |  34 +++++-
>  lib/flow.h                      |  27 +++--
>  lib/learn.c                     |   1 +
>  lib/match.c                     |  98 +++++++++++------
>  lib/meta-flow.c                 |  86 +++++++++++++--
>  lib/meta-flow.xml               | 156 +++++++++++++++++++++++----
>  lib/nx-match.c                  |  34 +++++-
>  lib/odp-util.c                  |  38 +++----
>  lib/ofp-parse.c                 |  12 +++
>  lib/ofp-util.c                  |  67 +++++++++---
>  ofproto/ofproto-dpif-xlate.c    |   1 +
>  ofproto/tunnel.c                |   2 -
>  tests/dpif-netdev.at            |  89 ++++++++--------
>  tests/odp.at                    |   1 +
>  tests/ofproto-dpif.at           | 230 ++++++++++++++++++++--------------------
>  tests/ofproto.at                |   1 +
>  tests/ovs-ofctl.at              |   2 +-
>  tests/pmd.at                    |   8 +-
>  tests/tunnel-push-pop-ipv6.at   |   2 +-
>  tests/tunnel-push-pop.at        |   2 +-
>  tests/tunnel.at                 |  18 ++--
>  24 files changed, 653 insertions(+), 284 deletions(-)
> 
> diff --git a/build-aux/extract-ofp-fields b/build-aux/extract-ofp-fields
> index d5b8a820251e..24dd756ad7d5 100755
> --- a/build-aux/extract-ofp-fields
> +++ b/build-aux/extract-ofp-fields
> @@ -36,7 +36,8 @@ FORMATTING = {"decimal":            ("MFS_DECIMAL",      1,   8),
>                "OpenFlow 1.1+ port": ("MFS_OFP_PORT_OXM", 4,   4),
>                "frag":               ("MFS_FRAG",         1,   1),
>                "tunnel flags":       ("MFS_TNL_FLAGS",    2,   2),
> -              "TCP flags":          ("MFS_TCP_FLAGS",    2,   2)}
> +              "TCP flags":          ("MFS_TCP_FLAGS",    2,   2),
> +              "packet type":        ("MFS_PACKET_TYPE",  4,   4)}
> 
>  PREREQS = {"none": "MFP_NONE",
>             "Ethernet": "MFP_ETHERNET",
> diff --git a/include/openvswitch/match.h b/include/openvswitch/match.h
> index 70da928fe47d..aca725265c79 100644
> --- a/include/openvswitch/match.h
> +++ b/include/openvswitch/match.h
> @@ -23,6 +23,7 @@
> 
>  struct ds;
>  struct ofputil_port_map;
> +struct mf_field;
> 
>  /* A flow classification match.
>   *
> @@ -119,6 +120,10 @@ void match_set_ct_ipv6_dst_masked(struct match *, const struct in6_addr *,
>                                    const struct in6_addr *);
> 
>  void match_set_packet_type(struct match *, ovs_be32 packet_type);
> +void match_set_default_packet_type(struct match *);
> +bool match_has_default_packet_type(const struct match *);
> +void match_add_ethernet_prereq(struct match *, const struct mf_field *);
> +
>  void match_set_skb_priority(struct match *, uint32_t skb_priority);
>  void match_set_dl_type(struct match *, ovs_be16);
>  void match_set_dl_src(struct match *, const struct eth_addr );
> diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
> index cbfd3ba65b73..fc109501d869 100644
> --- a/include/openvswitch/meta-flow.h
> +++ b/include/openvswitch/meta-flow.h
> @@ -133,6 +133,11 @@ struct ofputil_tlv_table_mod;
>   *
>   *       TCP flags: See the description of tcp_flags in ovs-ofctl(8).
>   *
> + *       packet type: A pair of packet type namespace NS and NS_TYPE within
> + *       that namespace "(NS,NS_TYPE)". NS and NS_TYPE are formatted in
> + *       decimal or hexadecimal as and accept decimal and hexadecimal (with
> + *       0x prefix) at parsing.
> + *
>   *   Prerequisites:
>   *
>   *     The field's prerequisites.  The values should be straightfoward.
> @@ -248,6 +253,20 @@ enum OVS_PACKED_ENUM mf_field_id {
>       */
>      MFF_RECIRC_ID,
> 
> +    /* "packet_type".
> +     *
> +     * Define the packet type in OpenFlow 1.5+.
> +     *
> +     * Type: be32.
> +     * Maskable: no.
> +     * Formatting: packet type.
> +     * Prerequisites: none.
> +     * Access: read-only.
> +     * NXM: none.
> +     * OXM: OXM_OF_PACKET_TYPE(44) since OF1.5 and v2.8.
> +     */
> +    MFF_PACKET_TYPE,
> +
>      /* "conj_id".
>       *
>       * ID for "conjunction" actions.  Please refer to ovs-ofctl(8)
> @@ -1860,6 +1879,7 @@ enum OVS_PACKED_ENUM mf_string {
>      MFS_FRAG,                   /* no, yes, first, later, not_later */
>      MFS_TNL_FLAGS,              /* FLOW_TNL_F_* flags */
>      MFS_TCP_FLAGS,              /* TCP_* flags */
> +    MFS_PACKET_TYPE,            /* "(NS,NS_TYPE)" */
>  };
> 
>  struct mf_field {
> diff --git a/lib/flow.c b/lib/flow.c
> index d73e796a2f45..6be645730f24 100644
> --- a/lib/flow.c
> +++ b/lib/flow.c
> @@ -1153,6 +1153,38 @@ format_flags_masked(struct ds *ds, const char *name,
>      }
>  }
> 
> +static void
> +put_u16_masked(struct ds *s, uint16_t value, uint16_t mask)
> +{
> +    if (!mask) {
> +        ds_put_char(s, '*');
> +    } else {
> +        if (value > 9) {
> +            ds_put_format(s, "0x%"PRIx16, value);
> +        } else {
> +            ds_put_format(s, "%"PRIu16, value);
> +        }
> +
> +        if (mask != UINT16_MAX) {
> +            ds_put_format(s, "/0x%"PRIx16, mask);
> +        }
> +    }
> +}
> +
> +void
> +format_packet_type_masked(struct ds *s, ovs_be32 value, ovs_be32 mask)
> +{
> +    if (value == htonl(PT_ETH) && mask == OVS_BE32_MAX) {
> +        ds_put_cstr(s, "eth");
> +    } else {
> +        ds_put_cstr(s, "packet_type=(");
> +        put_u16_masked(s, pt_ns(value), pt_ns(mask));
> +        ds_put_char(s, ',');
> +        put_u16_masked(s, pt_ns_type(value), pt_ns_type(mask));
> +        ds_put_char(s, ')');
> +    }
> +}
> +
>  /* Scans a string 's' of flags to determine their numerical value and
>   * returns the number of characters parsed using 'bit_to_string' to
>   * lookup flag names. Scanning continues until the character 'end' is
> @@ -1425,7 +1457,6 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc,
>          WC_MASK_FIELD(wc, tunnel.tp_dst);
>          WC_MASK_FIELD(wc, tunnel.gbp_id);
>          WC_MASK_FIELD(wc, tunnel.gbp_flags);
> -        WC_MASK_FIELD(wc, packet_type);
> 
>          if (!(flow->tunnel.flags & FLOW_TNL_F_UDPIF)) {
>              if (flow->tunnel.metadata.present.map) {
> @@ -1457,6 +1488,7 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc,
> 
>      /* actset_output wildcarded. */
> 
> +    WC_MASK_FIELD(wc, packet_type);
>      WC_MASK_FIELD(wc, dl_dst);
>      WC_MASK_FIELD(wc, dl_src);
>      WC_MASK_FIELD(wc, dl_type);
> diff --git a/lib/flow.h b/lib/flow.h
> index 68bd4f3c5149..f61d6c3aa106 100644
> --- a/lib/flow.h
> +++ b/lib/flow.h
> @@ -83,6 +83,7 @@ void format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t),
>  void format_flags_masked(struct ds *ds, const char *name,
>                           const char *(*bit_to_string)(uint32_t),
>                           uint32_t flags, uint32_t mask, uint32_t max_mask);
> +void format_packet_type_masked(struct ds *, ovs_be32 value, ovs_be32 mask);
>  int parse_flags(const char *s, const char *(*bit_to_string)(uint32_t),
>                  char end, const char *field_name, char **res_string,
>                  uint32_t *res_flags, uint32_t allowed, uint32_t *res_mask);
> @@ -964,9 +965,23 @@ static inline bool is_ethernet(const struct flow *flow,
>      return flow->packet_type == htonl(PT_ETH);
>  }
> 
> +static inline ovs_be16 get_dl_type(const struct flow *flow)
> +{
> +    if (flow->packet_type == htonl(PT_ETH)) {
> +        return flow->dl_type;
> +    } else if (pt_ns(flow->packet_type) == OFPHTN_ETHERTYPE) {
> +        return pt_ns_type_be(flow->packet_type);
> +    } else {
> +        return htons(FLOW_DL_TYPE_NONE);
> +    }
> +}
> +
>  static inline bool is_vlan(const struct flow *flow,
>                             struct flow_wildcards *wc)
>  {
> +    if (!is_ethernet(flow, wc)) {
> +        return false;
> +    }
>      if (wc) {
>          WC_MASK_FIELD_MASK(wc, vlans[0].tci, htons(VLAN_CFI));
>      }
> @@ -975,7 +990,7 @@ static inline bool is_vlan(const struct flow *flow,
> 
>  static inline bool is_ip_any(const struct flow *flow)
>  {
> -    return dl_type_is_ip_any(flow->dl_type);
> +    return dl_type_is_ip_any(get_dl_type(flow));
>  }
> 
>  static inline bool is_ip_proto(const struct flow *flow, uint8_t ip_proto,
> @@ -1011,7 +1026,7 @@ static inline bool is_sctp(const struct flow *flow,
>  static inline bool is_icmpv4(const struct flow *flow,
>                               struct flow_wildcards *wc)
>  {
> -    if (flow->dl_type == htons(ETH_TYPE_IP)) {
> +    if (get_dl_type(flow) == htons(ETH_TYPE_IP)) {
>          if (wc) {
>              memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
>          }
> @@ -1023,7 +1038,7 @@ static inline bool is_icmpv4(const struct flow *flow,
>  static inline bool is_icmpv6(const struct flow *flow,
>                               struct flow_wildcards *wc)
>  {
> -    if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
> +    if (get_dl_type(flow) == htons(ETH_TYPE_IPV6)) {
>          if (wc) {
>              memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
>          }
> @@ -1054,7 +1069,7 @@ static inline bool is_nd(const struct flow *flow,
> 
>  static inline bool is_igmp(const struct flow *flow, struct flow_wildcards *wc)
>  {
> -    if (flow->dl_type == htons(ETH_TYPE_IP)) {
> +    if (get_dl_type(flow) == htons(ETH_TYPE_IP)) {
>          if (wc) {
>              memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
>          }
> @@ -1098,8 +1113,8 @@ static inline bool is_mld_report(const struct flow *flow,
> 
>  static inline bool is_stp(const struct flow *flow)
>  {
> -    return (eth_addr_equals(flow->dl_dst, eth_addr_stp)
> -            && flow->dl_type == htons(FLOW_DL_TYPE_NONE));
> +    return (flow->dl_type == htons(FLOW_DL_TYPE_NONE)
> +            && eth_addr_equals(flow->dl_dst, eth_addr_stp));
>  }
> 
>  #endif /* flow.h */
> diff --git a/lib/learn.c b/lib/learn.c
> index bc5a6eb2d16f..4658b8611857 100644
> --- a/lib/learn.c
> +++ b/lib/learn.c
> @@ -139,6 +139,7 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow,
>          switch (spec->dst_type) {
>          case NX_LEARN_DST_MATCH:
>              mf_write_subfield(&spec->dst, &value, &fm->match);
> +            match_add_ethernet_prereq(&fm->match, spec->dst.field);
>              mf_vl_mff_set_tlv_bitmap(
>                  spec->dst.field, &fm->match.flow.tunnel.metadata.present.map);
>              break;
> diff --git a/lib/match.c b/lib/match.c
> index 9aa0d888519c..f5288e31f399 100644
> --- a/lib/match.c
> +++ b/lib/match.c
> @@ -496,6 +496,49 @@ match_set_packet_type(struct match *match, ovs_be32 packet_type)
>      match->wc.masks.packet_type = OVS_BE32_MAX;
>  }
> 
> +/* If 'match' does not match on any packet type, make it match on Ethernet
> + * packets (the default packet type, as specified by OpenFlow). */
> +void
> +match_set_default_packet_type(struct match *match)
> +{
> +    if (!match->wc.masks.packet_type) {
> +        match_set_packet_type(match, htonl(PT_ETH));
> +    }
> +}
> +
> +/* Returns true if 'match' matches only Ethernet packets (the default packet
> + * type, as specified by OpenFlow). */
> +bool
> +match_has_default_packet_type(const struct match *match)
> +{
> +    return (match->flow.packet_type == htonl(PT_ETH)
> +            && match->wc.masks.packet_type == OVS_BE32_MAX);
> +}
> +
> +/* A match on 'field' is being added to or has been added to 'match'.  If
> + * 'field' is a data field, and 'match' does not already match on packet_type,
> + * this function make it match on the Ethernet packet_type.
> + *
> + * This function is useful because OpenFlow implicitly applies to Ethernet
> + * packets when there's no explicit packet_type, but matching on a metadata
> + * field doesn't imply anything about the packet_type and falsely inferring
> + * that it does can cause harm.  A flow that matches only on metadata fields,
> + * for example, should be able to match more than just Ethernet flows.  There
> + * are also important reasons that a catch-all match (one with no field matches
> + * at all) should not imply a packet_type(0,0) match.  For example, a "flow
> + * dump" request that matches on no fields should return every flow in the
> + * switch, not just the flows that match on Ethernet.  As a second example,
> + * OpenFlow 1.2+ special-cases "table miss" flows, that is catch-all flows with
> + * priority 0, and inferring a match on packet_type(0,0) causes such a flow not
> + * to be a table miss flow.  */
> +void
> +match_add_ethernet_prereq(struct match *match, const struct mf_field *field)
> +{
> +    if (field->prereqs != MFP_NONE) {
> +        match_set_default_packet_type(match);
> +    }
> +}
> +
>  void
>  match_set_dl_type(struct match *match, ovs_be16 dl_type)
>  {
> @@ -1187,8 +1230,8 @@ match_format(const struct match *match,
>      size_t start_len = s->length;
>      const struct flow *f = &match->flow;
>      bool skip_type = false;
> -
>      bool skip_proto = false;
> +    ovs_be16 dl_type = f->dl_type;
> 
>      int i;
> 
> @@ -1269,25 +1312,18 @@ match_format(const struct match *match,
>          format_be16_masked(s, "ct_tp_dst", f->ct_tp_dst, wc->masks.ct_tp_dst);
>      }
> 
> -    if (wc->masks.packet_type) {
> -        if (pt_ns_type_be(wc->masks.packet_type) == 0) {
> -            ds_put_format(s, "packet_type=(%u,*),",
> -                          pt_ns(f->packet_type));
> -        } else if (pt_ns_type_be(wc->masks.packet_type) == OVS_BE16_MAX) {
> -            ds_put_format(s, "packet_type=(%u,%#"PRIx16"),",
> -                          pt_ns(f->packet_type),
> -                          pt_ns_type(f->packet_type));
> -        } else {
> -            ds_put_format(s, "packet_type=(%u,%#"PRIx16"/%#"PRIx16"),",
> -                          pt_ns(f->packet_type),
> -                          pt_ns_type(f->packet_type),
> -                          pt_ns_type(wc->masks.packet_type));
> +    if (wc->masks.packet_type && !match_has_default_packet_type(match)) {
> +        format_packet_type_masked(s, f->packet_type, wc->masks.packet_type);
> +        ds_put_char(s, ',');
> +        if (pt_ns(f->packet_type) == OFPHTN_ETHERTYPE) {
> +            dl_type = pt_ns_type_be(f->packet_type);
>          }
>      }
> 
>      if (wc->masks.dl_type) {
> +        dl_type = f->dl_type;
>          skip_type = true;
> -        if (f->dl_type == htons(ETH_TYPE_IP)) {
> +        if (dl_type == htons(ETH_TYPE_IP)) {
>              if (wc->masks.nw_proto) {
>                  skip_proto = true;
>                  if (f->nw_proto == IPPROTO_ICMP) {
> @@ -1307,7 +1343,7 @@ match_format(const struct match *match,
>              } else {
>                  ds_put_format(s, "%sip%s,", colors.value, colors.end);
>              }
> -        } else if (f->dl_type == htons(ETH_TYPE_IPV6)) {
> +        } else if (dl_type == htons(ETH_TYPE_IPV6)) {
>              if (wc->masks.nw_proto) {
>                  skip_proto = true;
>                  if (f->nw_proto == IPPROTO_ICMPV6) {
> @@ -1325,13 +1361,13 @@ match_format(const struct match *match,
>              } else {
>                  ds_put_format(s, "%sipv6%s,", colors.value, colors.end);
>              }
> -        } else if (f->dl_type == htons(ETH_TYPE_ARP)) {
> +        } else if (dl_type == htons(ETH_TYPE_ARP)) {
>              ds_put_format(s, "%sarp%s,", colors.value, colors.end);
> -        } else if (f->dl_type == htons(ETH_TYPE_RARP)) {
> +        } else if (dl_type == htons(ETH_TYPE_RARP)) {
>              ds_put_format(s, "%srarp%s,", colors.value, colors.end);
> -        } else if (f->dl_type == htons(ETH_TYPE_MPLS)) {
> +        } else if (dl_type == htons(ETH_TYPE_MPLS)) {
>              ds_put_format(s, "%smpls%s,", colors.value, colors.end);
> -        } else if (f->dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
> +        } else if (dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
>              ds_put_format(s, "%smplsm%s,", colors.value, colors.end);
>          } else {
>              skip_type = false;
> @@ -1403,9 +1439,9 @@ match_format(const struct match *match,
> 
>      if (!skip_type && wc->masks.dl_type) {
>          ds_put_format(s, "%sdl_type=%s0x%04"PRIx16",",
> -                      colors.param, colors.end, ntohs(f->dl_type));
> +                      colors.param, colors.end, ntohs(dl_type));
>      }
> -    if (f->dl_type == htons(ETH_TYPE_IPV6)) {
> +    if (dl_type == htons(ETH_TYPE_IPV6)) {
>          format_ipv6_netmask(s, "ipv6_src", &f->ipv6_src, &wc->masks.ipv6_src);
>          format_ipv6_netmask(s, "ipv6_dst", &f->ipv6_dst, &wc->masks.ipv6_dst);
>          if (wc->masks.ipv6_label) {
> @@ -1419,8 +1455,8 @@ match_format(const struct match *match,
>                                ntohl(wc->masks.ipv6_label));
>              }
>          }
> -    } else if (f->dl_type == htons(ETH_TYPE_ARP) ||
> -               f->dl_type == htons(ETH_TYPE_RARP)) {
> +    } else if (dl_type == htons(ETH_TYPE_ARP) ||
> +               dl_type == htons(ETH_TYPE_RARP)) {
>          format_ip_netmask(s, "arp_spa", f->nw_src, wc->masks.nw_src);
>          format_ip_netmask(s, "arp_tpa", f->nw_dst, wc->masks.nw_dst);
>      } else {
> @@ -1428,8 +1464,8 @@ match_format(const struct match *match,
>          format_ip_netmask(s, "nw_dst", f->nw_dst, wc->masks.nw_dst);
>      }
>      if (!skip_proto && wc->masks.nw_proto) {
> -        if (f->dl_type == htons(ETH_TYPE_ARP) ||
> -            f->dl_type == htons(ETH_TYPE_RARP)) {
> +        if (dl_type == htons(ETH_TYPE_ARP) ||
> +            dl_type == htons(ETH_TYPE_RARP)) {
>              ds_put_format(s, "%sarp_op=%s%"PRIu8",",
>                            colors.param, colors.end, f->nw_proto);
>          } else {
> @@ -1437,8 +1473,8 @@ match_format(const struct match *match,
>                            colors.param, colors.end, f->nw_proto);
>          }
>      }
> -    if (f->dl_type == htons(ETH_TYPE_ARP) ||
> -        f->dl_type == htons(ETH_TYPE_RARP)) {
> +    if (dl_type == htons(ETH_TYPE_ARP) ||
> +        dl_type == htons(ETH_TYPE_RARP)) {
>          format_eth_masked(s, "arp_sha", f->arp_sha, wc->masks.arp_sha);
>          format_eth_masked(s, "arp_tha", f->arp_tha, wc->masks.arp_tha);
>      }
> @@ -1491,15 +1527,15 @@ match_format(const struct match *match,
>                        f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "not_later");
>          break;
>      }
> -    if (f->dl_type == htons(ETH_TYPE_IP) &&
> +    if (dl_type == htons(ETH_TYPE_IP) &&
>          f->nw_proto == IPPROTO_ICMP) {
>          format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
>          format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
> -    } else if (f->dl_type == htons(ETH_TYPE_IP) &&
> +    } else if (dl_type == htons(ETH_TYPE_IP) &&
>                 f->nw_proto == IPPROTO_IGMP) {
>          format_be16_masked(s, "igmp_type", f->tp_src, wc->masks.tp_src);
>          format_be16_masked(s, "igmp_code", f->tp_dst, wc->masks.tp_dst);
> -    } else if (f->dl_type == htons(ETH_TYPE_IPV6) &&
> +    } else if (dl_type == htons(ETH_TYPE_IPV6) &&
>                 f->nw_proto == IPPROTO_ICMPV6) {
>          format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
>          format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
> diff --git a/lib/meta-flow.c b/lib/meta-flow.c
> index a255f1ce9de1..d0980814c36c 100644
> --- a/lib/meta-flow.c
> +++ b/lib/meta-flow.c
> @@ -205,6 +205,8 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
>          return !wc->masks.dp_hash;
>      case MFF_RECIRC_ID:
>          return !wc->masks.recirc_id;
> +    case MFF_PACKET_TYPE:
> +        return !wc->masks.packet_type;
>      case MFF_CONJ_ID:
>          return !wc->masks.conj_id;
>      case MFF_TUN_SRC:
> @@ -401,22 +403,24 @@ mf_are_prereqs_ok__(const struct mf_field *mf, const struct flow *flow,
>                      const struct flow_wildcards *mask,
>                      struct flow_wildcards *wc)
>  {
> +    ovs_be16 dl_type = get_dl_type(flow);
> +
>      switch (mf->prereqs) {
>      case MFP_NONE:
>          return true;
>      case MFP_ETHERNET:
>          return is_ethernet(flow, wc);
>      case MFP_ARP:
> -        return (flow->dl_type == htons(ETH_TYPE_ARP) ||
> -                flow->dl_type == htons(ETH_TYPE_RARP));
> +        return (dl_type == htons(ETH_TYPE_ARP) ||
> +                dl_type == htons(ETH_TYPE_RARP));
>      case MFP_IPV4:
> -        return flow->dl_type == htons(ETH_TYPE_IP);
> +        return dl_type == htons(ETH_TYPE_IP);
>      case MFP_IPV6:
> -        return flow->dl_type == htons(ETH_TYPE_IPV6);
> +        return dl_type == htons(ETH_TYPE_IPV6);
>      case MFP_VLAN_VID:
>          return is_vlan(flow, wc);
>      case MFP_MPLS:
> -        return eth_type_mpls(flow->dl_type);
> +        return eth_type_mpls(dl_type);
>      case MFP_IP_ANY:
>          return is_ip_any(flow);
>      case MFP_CT_VALID:
> @@ -476,6 +480,7 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
>      switch (mf->id) {
>      case MFF_DP_HASH:
>      case MFF_RECIRC_ID:
> +    case MFF_PACKET_TYPE:
>      case MFF_CONJ_ID:
>      case MFF_TUN_ID:
>      case MFF_TUN_SRC:
> @@ -600,6 +605,9 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
>      case MFF_RECIRC_ID:
>          value->be32 = htonl(flow->recirc_id);
>          break;
> +    case MFF_PACKET_TYPE:
> +        value->be32 = flow->packet_type;
> +        break;
>      case MFF_CONJ_ID:
>          value->be32 = htonl(flow->conj_id);
>          break;
> @@ -883,6 +891,9 @@ mf_set_value(const struct mf_field *mf,
>      case MFF_RECIRC_ID:
>          match_set_recirc_id(match, ntohl(value->be32));
>          break;
> +    case MFF_PACKET_TYPE:
> +        match_set_packet_type(match, value->be32);
> +        break;
>      case MFF_CONJ_ID:
>          match_set_conj_id(match, ntohl(value->be32));
>          break;
> @@ -1248,6 +1259,9 @@ mf_set_flow_value(const struct mf_field *mf,
>      case MFF_RECIRC_ID:
>          flow->recirc_id = ntohl(value->be32);
>          break;
> +    case MFF_PACKET_TYPE:
> +        flow->packet_type = value->be32;
> +        break;
>      case MFF_CONJ_ID:
>          flow->conj_id = ntohl(value->be32);
>          break;
> @@ -1292,7 +1306,6 @@ mf_set_flow_value(const struct mf_field *mf,
>      case MFF_IN_PORT:
>          flow->in_port.ofp_port = u16_to_ofp(ntohs(value->be16));
>          break;
> -
>      case MFF_IN_PORT_OXM:
>          ofputil_port_from_ofp11(value->be32, &flow->in_port.ofp_port);
>          break;
> @@ -1574,6 +1587,7 @@ mf_is_pipeline_field(const struct mf_field *mf)
>      CASE_MFF_REGS:
>      CASE_MFF_XREGS:
>      CASE_MFF_XXREGS:
> +    case MFF_PACKET_TYPE:
>          return true;
> 
>      case MFF_DP_HASH:
> @@ -1688,6 +1702,10 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
>          match->flow.recirc_id = 0;
>          match->wc.masks.recirc_id = 0;
>          break;
> +    case MFF_PACKET_TYPE:
> +        match->flow.packet_type = 0;
> +        match->wc.masks.packet_type = 0;
> +        break;
>      case MFF_CONJ_ID:
>          match->flow.conj_id = 0;
>          match->wc.masks.conj_id = 0;
> @@ -2021,6 +2039,7 @@ mf_set(const struct mf_field *mf,
>      case MFF_CT_TP_SRC:
>      case MFF_CT_TP_DST:
>      case MFF_RECIRC_ID:
> +    case MFF_PACKET_TYPE:
>      case MFF_CONJ_ID:
>      case MFF_IN_PORT:
>      case MFF_IN_PORT_OXM:
> @@ -2386,6 +2405,44 @@ syntax_error:
>  }
> 
>  static char *
> +mf_from_packet_type_string(const char *s, ovs_be32 *packet_type)
> +{
> +    char *tail;
> +    const char *err_str = "";
> +    int err;
> +
> +    if (*s != '(') {
> +        err_str = "missing '('";
> +        goto syntax_error;
> +    }
> +    s++;
> +    err = parse_int_string(s, (uint8_t *)packet_type, 2, &tail);
> +    if (err) {
> +        err_str = "ns";
> +        goto syntax_error;
> +    }
> +    if (*tail != ',') {
> +        err_str = "missing ','";
> +        goto syntax_error;
> +    }
> +    s = tail + 1;
> +    err = parse_int_string(s, ((uint8_t *)packet_type) + 2, 2, &tail);
> +    if (err) {
> +        err_str = "ns_type";
> +        goto syntax_error;
> +    }
> +    if (*tail != ')') {
> +        err_str = "missing ')'";
> +        goto syntax_error;
> +    }
> +
> +    return NULL;
> +
> +syntax_error:
> +    return xasprintf("%s: bad syntax for packet type %s", s, err_str);
> +}
> +
> +static char *
>  mf_from_ethernet_string(const struct mf_field *mf, const char *s,
>                          struct eth_addr *mac, struct eth_addr *mask)
>  {
> @@ -2623,6 +2680,12 @@ mf_parse(const struct mf_field *mf, const char *s,
>          error = mf_from_tcp_flags_string(s, &value->be16, &mask->be16);
>          break;
> 
> +    case MFS_PACKET_TYPE:
> +        ovs_assert(mf->n_bytes == sizeof(ovs_be32));
> +        error = mf_from_packet_type_string(s, &value->be32);
> +        mask->be32 = OVS_BE32_MAX;
> +        break;
> +
>      default:
>          OVS_NOT_REACHED();
>      }
> @@ -2717,6 +2780,12 @@ mf_format_ct_state_string(ovs_be32 value, ovs_be32 mask, struct ds *s)
>                          ntohl(mask), UINT16_MAX);
>  }
> 
> +static void
> +mf_format_packet_type_string(ovs_be32 value, ovs_be32 mask, struct ds *s)
> +{
> +    format_packet_type_masked(s, value, mask);
> +}
> +
>  /* Appends to 's' a string representation of field 'mf' whose value is in
>   * 'value' and 'mask'.  'mask' may be NULL to indicate an exact match. */
>  void
> @@ -2785,6 +2854,11 @@ mf_format(const struct mf_field *mf,
>                                     mask ? mask->be16 : OVS_BE16_MAX, s);
>          break;
> 
> +    case MFS_PACKET_TYPE:
> +        mf_format_packet_type_string(value->be32,
> +                                     mask ? mask->be32 : OVS_BE32_MAX, s);
> +        break;
> +
>      default:
>          OVS_NOT_REACHED();
>      }
> diff --git a/lib/meta-flow.xml b/lib/meta-flow.xml
> index 5efd431004dd..856e1ba8cf7b 100644
> --- a/lib/meta-flow.xml
> +++ b/lib/meta-flow.xml
> @@ -22,26 +22,38 @@
>    </p>
> 
>    <p>
> -    Some data fields, called <dfn>root fields</dfn>, are always present as a
> -    consequence of the basic networking technology in use.  The Ethernet header
> -    fields are root fields in current versions of Open vSwitch, though future
> -    versions might support other roots.  (Currently, to support LISP tunnels,
> -    which do not encapsulate an Ethernet header, Open vSwitch synthesizes one.)
> +    Data fields that are always present as a consequence of the basic
> +    networking technology in use are called called <dfn>root fields</dfn>.
> +    Open vSwitch 2.7 and earlier considered Ethernet fields to be root fields,
> +    and this remains the default mode of operation for Open vSwitch bridges.
> +    In this mode, when a packet is received from a non-Ethernet interfaces,
> +    such as a layer-3 LISP or GRE tunnel, Open vSwitch force-fits it to this
> +    Ethernet-centric point of view by pretending that an Ethernet header is
> +    present whose Ethernet type that indicates the packet's actual type (and
> +    whose source and destination addresses are all-zero).
>    </p>
> 
> -  <!-- future directions: EXT-112 -->
>    <p>
> -    Other data fields are not always present.  A packet contains ARP fields,
> -    for example, only when its Ethernet header indicates the Ethertype for ARP,
> +    Open vSwitch 2.8 and later supports the ``packet type-aware pipeline''
> +    concept introduced in OpenFlow 1.5.  A bridge configured to be packet
> +    type-aware can handle packets of multiple networking technologies, such as
> +    Ethernet, IP, ARP, MPLS, or NSH in parallel.  Such a bridge does not have
> +    any root fields.
> +  </p>
> +
> +  <p>
> +    Non-root data fields are not always present.  A packet contains ARP
> +    fields, for example, only when its packet type is ARP or when it is an
> +    Ethernet packet whose Ethernet header indicates the Ethertype for ARP,
>      0x0806.  In this documentation, we say that a field is
>      <dfn>applicable</dfn> when it is present in a packet, and
>      <dfn>inapplicable</dfn> when it is not.  (These are not standard terms.)
>      We refer to the conditions that determine whether a field is applicable as
>      <dfn>prerequisites</dfn>.  Some VLAN-related fields are a special case:
> -    these fields are always applicable, but have a designated value or bit that
> -    indicates whether a VLAN header is present, with the remaining values or
> -    bits indicating the VLAN header's content (if it is present).  <!-- XXX
> -    also ethertype -->
> +    these fields are always applicable for Ethernet packets, but have a
> +    designated value or bit that indicates whether a VLAN header is present,
> +    with the remaining values or bits indicating the VLAN header's content
> +    (if it is present).  <!-- XXX also ethertype -->
>    </p>
> 
>    <p>
> @@ -51,7 +63,8 @@
>      example, one may match (see <cite>Matching</cite>, below) a given
>      field only if the match includes the field's prerequisite,
>      e.g. matching an ARP field is only allowed if one also matches on
> -    Ethertype 0x0806.
> +    Ethertype 0x0806 or the <ref field="packet_type"/> for ARP in a packet
> +    type-aware bridge.
>    </p>
> 
>    <p>
> @@ -301,6 +314,8 @@ tcp,tp_src=0x07c0/0xfff0
>    </p>
> 
>    <dl>
> +    <dt><code>eth</code></dt>
> +    <dd><code>packet_type=(0,0)</code> (Open vSwitch 2.8 and later)</dd>
>      <dt><code>ip</code></dt>     <dd><code>eth_type=0x0800</code></dd>
>      <dt><code>ipv6</code></dt>   <dd><code>eth_type=0x86dd</code></dd>
>      <dt><code>icmp</code></dt>   <dd><code>eth_type=0x0800,ip_proto=1</code></dd>
> @@ -317,6 +332,15 @@ tcp,tp_src=0x07c0/0xfff0
>      <dt><code>mplsm</code></dt>  <dd><code>eth_type=0x8848</code></dd>
>    </dl>
> 
> +  <p>
> +    These shorthand notations continue to work in packet type-aware bridges.
> +    The absence of a packet_type match implies
> +    <code>packet_type=ethernet</code>, so that shorthands match on Ethernet
> +    packets with the implied eth_type. Please note that the shorthand
> +    <code>ip</code> does not match packets of packet_type (1,0x800) for IPv4.
> +  </p>
> +
> +
>    <h2>Evolution of OpenFlow Fields</h2>
> 
>    <p>
> @@ -802,20 +826,12 @@ tcp,tp_src=0x07c0/0xfff0
>    </p>
> 
>    <ul>
> +    <li>Packet type.</li>
>      <li>TCP flags.</li>
>      <li>Packet registers.</li>
>      <li>The output port in the OpenFlow action set.</li>
>    </ul>
> 
> -  <p>
> -    OpenFlow 1.5 also added OXMs for the following fields not documented here
> -    and not yet implemented by Open vSwitch:
> -  </p>
> -
> -  <ul>
> -    <li>Packet type.</li>
> -  </ul>
> -
>    <h1>Fields Reference</h1>
> 
>    <p>
> @@ -2273,6 +2289,102 @@ actions=clone(load:0->NXM_OF_IN_PORT[],output:123)
> 
>      <field id="MFF_DP_HASH" title="Datapath Hash" internal="yes"/>
>      <field id="MFF_RECIRC_ID" title="Datapath Recirculation ID" internal="yes"/>
> +
> +    <field id="MFF_PACKET_TYPE" title="Packet Type">
> +      <p>
> +        The type of the packet in the format specified in OpenFlow 1.5:
> +      </p>
> +
> +      <diagram>
> +	<header name="Packet type">
> +	  <bits name="ns" above="16" width=".75"/>
> +	  <bits name="ns_type" above="16" width=".75"/>
> +	</header>
> +	<dots/>
> +      </diagram>
> +
> +      <p>
> +        The upper 16 bits, <var>ns</var>, are a namespace.  The meaning of
> +        <var>ns_type</var> depends on the namespace.  The packet type field is
> +        specified and displayed in the format
> +        <code>(<var>ns</var>,<var>ns_type</var>)</code>.
> +      </p>
> +
> +      <p>
> +        Open vSwitch currently supports the following classes of packet types
> +        for matching:
> +        <dl>
> +          <dt><code>(0,0)</code></dt>
> +            <dd>Ethernet.</dd>
> +          <dt><code>(1,<var>ethertype</var>)</code></dt>
> +          <dd>
> +            <p>
> +              The specified <var>ethertype</var>.  Open vSwitch can forward
> +              packets with any <var>ethertype</var>, but it can only match on
> +              and process data fields for the following supported packet types:
> +            </p>
> +            <dl>
> +              <dt><code>(1,0x800)</code></dt>  <dd>IPv4</dd>
> +              <dt><code>(1,0x806)</code></dt>  <dd>ARP</dd>
> +              <dt><code>(1,0x86dd)</code></dt> <dd>IPv6</dd>
> +              <dt><code>(1,0x8847)</code></dt> <dd>MPLS</dd>
> +              <dt><code>(1,0x8848)</code></dt> <dd>MPLS multicast</dd>
> +              <dt><code>(1,0x8035)</code></dt> <dd>RARP</dd>
> +              <dt><code>(1,0x894f)</code></dt> <dd>NSH</dd>
> +            </dl>
> +          </dd>
> +        </dl>
> +      </p>
> +
> +      <p>
> +        Consider the distinction between a packet with <code>packet_type=(0,0),
> +        dl_type=0x800</code> and one with <code>packet_type=(1,0x800)</code>.
> +        The former is an Ethernet frame that contains an IPv4 packet, like
> +        this:
> +      </p>
> +
> +      <diagram>
> +	<header name="Ethernet">
> +	  <bits name="dst" above="48" width="0.4"/>
> +	  <bits name="src" above="48" width="0.4"/>
> +	  <bits name="type" above="16" below="0x800" width="0.4"/>
> +	</header>
> +	<header name="IPv4">
> +	  <bits name="..." width="0.4"/>
> +	  <bits name="proto" above="8" width="0.4"/>
> +	  <bits name="src" above="32" width="0.4"/>
> +	  <bits name="dst" above="32" width="0.4"/>
> +	</header>
> +	<dots/>
> +      </diagram>
> +
> +      <p>
> +        The latter is an IPv4 packet not encapsulated inside any outer frame,
> +        like this:
> +      </p>
> +
> +      <diagram>
> +	<header name="IPv4">
> +	  <bits name="..." width="0.4"/>
> +	  <bits name="proto" above="8" width="0.4"/>
> +	  <bits name="src" above="32" width="0.4"/>
> +	  <bits name="dst" above="32" width="0.4"/>
> +	</header>
> +	<dots/>
> +      </diagram>
> +
> +      <p>
> +        Matching on <ref field="packet_type"/> is a pre-requisite for matching
> +        on any data field, but for backward compatibility, when a match on a
> +        data field is present without a <ref field="packet_type"/> match, Open
> +        vSwitch acts as though a match on <code>(0,0)</code> (Ethernet) had
> +        been supplied.  Similarly, when Open vSwitch sends flow match
> +        information to a controller, e.g. in a reply to a request to dump the
> +        flow table, Open vSwitch omits a match on packet type (0,0) if it would
> +        be implied by a data field match.
> +      </p>
> +    </field>
> +
>    </group>
> 
>    <group title="Connection Tracking">
> diff --git a/lib/nx-match.c b/lib/nx-match.c
> index 6278b7758783..cb0cad8458b9 100644
> --- a/lib/nx-match.c
> +++ b/lib/nx-match.c
> @@ -561,6 +561,8 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
>                  free(err_str);
>                  return OFPERR_OFPBMC_BAD_VALUE;
>              }
> +
> +            match_add_ethernet_prereq(match, field);
>          }
> 
>          if (error) {
> @@ -775,6 +777,7 @@ oxm_pull_field_array(const void *fields_data, size_t fields_len,
> 
>  struct nxm_put_ctx {
>      struct ofpbuf *output;
> +    bool implied_ethernet;
>  };
> 
>  void
> @@ -795,6 +798,9 @@ nxm_put__(struct nxm_put_ctx *ctx,
>            const void *value, const void *mask, size_t n_bytes)
>  {
>      nxm_put_entry_raw(ctx->output, field, version, value, mask, n_bytes);
> +    if (!ctx->implied_ethernet && mf_from_id(field)->prereqs != MFP_NONE) {
> +        ctx->implied_ethernet = true;
> +    }
>  }
> 
>  static void
> @@ -904,8 +910,9 @@ nxm_put_ip(struct nxm_put_ctx *ctx,
>             const struct match *match, enum ofp_version oxm)
>  {
>      const struct flow *flow = &match->flow;
> +    ovs_be16 dl_type = get_dl_type(flow);
> 
> -    if (flow->dl_type == htons(ETH_TYPE_IP)) {
> +    if (dl_type == htons(ETH_TYPE_IP)) {
>          nxm_put_32m(ctx, MFF_IPV4_SRC, oxm,
>                      flow->nw_src, match->wc.masks.nw_src);
>          nxm_put_32m(ctx, MFF_IPV4_DST, oxm,
> @@ -1014,12 +1021,19 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
>  {
>      const struct flow *flow = &match->flow;
>      const size_t start_len = b->size;
> +    ovs_be16 dl_type = get_dl_type(flow);
>      int match_len;
>      int i;
> 
>      BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
> 
> -    struct nxm_put_ctx ctx = { .output = b };
> +    struct nxm_put_ctx ctx = { .output = b, .implied_ethernet = false };
> +
> +    /* OpenFlow Packet Type. Must be first. */
> +    if (match->wc.masks.packet_type && !match_has_default_packet_type(match)) {
> +        nxm_put_32m(&ctx, MFF_PACKET_TYPE, oxm, flow->packet_type,
> +                    match->wc.masks.packet_type);
> +    }
> 
>      /* Metadata. */
>      if (match->wc.masks.dp_hash) {
> @@ -1082,7 +1096,7 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
>      }
> 
>      /* MPLS. */
> -    if (eth_type_mpls(flow->dl_type)) {
> +    if (eth_type_mpls(dl_type)) {
>          if (match->wc.masks.mpls_lse[0] & htonl(MPLS_TC_MASK)) {
>              nxm_put_8(&ctx, MFF_MPLS_TC, oxm,
>                        mpls_lse_to_tc(flow->mpls_lse[0]));
> @@ -1102,8 +1116,8 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
>      /* L3. */
>      if (is_ip_any(flow)) {
>          nxm_put_ip(&ctx, match, oxm);
> -    } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
> -               flow->dl_type == htons(ETH_TYPE_RARP)) {
> +    } else if (dl_type == htons(ETH_TYPE_ARP) ||
> +               dl_type == htons(ETH_TYPE_RARP)) {
>          /* ARP. */
>          if (match->wc.masks.nw_proto) {
>              nxm_put_16(&ctx, MFF_ARP_OP, oxm,
> @@ -1198,6 +1212,16 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
>          }
>      }
> 
> +    if (match_has_default_packet_type(match) && !ctx.implied_ethernet) {
> +        uint64_t pt_stub[16 / 8];
> +        struct ofpbuf pt;
> +        ofpbuf_use_stack(&pt, pt_stub, sizeof pt_stub);
> +        nxm_put_entry_raw(&pt, MFF_PACKET_TYPE, oxm, &flow->packet_type,
> +                          NULL, sizeof flow->packet_type);
> +
> +        ofpbuf_insert(b, start_len, pt.data, pt.size);
> +    }
> +
>      match_len = b->size - start_len;
>      return match_len;
>  }
> diff --git a/lib/odp-util.c b/lib/odp-util.c
> index 6c2ab6cc5799..ef8651247751 100644
> --- a/lib/odp-util.c
> +++ b/lib/odp-util.c
> @@ -2983,23 +2983,18 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
>          break;
> 
>      case OVS_KEY_ATTR_PACKET_TYPE: {
> -        ovs_be32 packet_type = nl_attr_get_be32(a);
> -        uint16_t ns = pt_ns(packet_type);
> -        uint16_t ns_type = pt_ns_type(packet_type);
> +        ovs_be32 value = nl_attr_get_be32(a);
> +        ovs_be32 mask = ma ? nl_attr_get_be32(ma) : OVS_BE32_MAX;
> 
> -        if (!is_exact) {
> -            ovs_be32 mask = nl_attr_get_be32(ma);
> -            uint16_t mask_ns_type = pt_ns_type(mask);
> +        ovs_be16 ns = htons(pt_ns(value));
> +        ovs_be16 ns_mask = htons(pt_ns(mask));
> +        format_be16(ds, "ns", ns, &ns_mask, verbose);
> 
> -            if (mask == 0) {
> -                ds_put_format(ds, "ns=%u,id=*", ns);
> -            } else {
> -                ds_put_format(ds, "ns=%u,id=%#"PRIx16"/%#"PRIx16,
> -                              ns, ns_type, mask_ns_type);
> -            }
> -        } else {
> -            ds_put_format(ds, "ns=%u,id=%#"PRIx16, ns, ns_type);
> -        }
> +        ovs_be16 ns_type = pt_ns_type_be(value);
> +        ovs_be16 ns_type_mask = pt_ns_type_be(mask);
> +        format_be16(ds, "id", ns_type, &ns_type_mask, verbose);
> +
> +        ds_chomp(ds, ',');
>          break;
>      }
> 
> @@ -4340,6 +4335,15 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
>          SCAN_FIELD("tll=", eth, nd_tll);
>      } SCAN_END(OVS_KEY_ATTR_ND);
> 
> +    struct packet_type {
> +        ovs_be16 ns;
> +        ovs_be16 id;
> +    };
> +    SCAN_BEGIN("packet_type(", struct packet_type) {
> +        SCAN_FIELD("ns=", be16, ns);
> +        SCAN_FIELD("id=", be16, id);
> +    } SCAN_END(OVS_KEY_ATTR_PACKET_TYPE);
> +
>      /* Encap open-coded. */
>      if (!strncmp(s, "encap(", 6)) {
>          const char *start = s;
> @@ -4527,9 +4531,7 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms,
>          nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, data->in_port.odp_port);
>      }
> 
> -    if (export_mask || flow->packet_type != htonl(PT_ETH)) {
> -        nl_msg_put_be32(buf, OVS_KEY_ATTR_PACKET_TYPE, data->packet_type);
> -    }
> +    nl_msg_put_be32(buf, OVS_KEY_ATTR_PACKET_TYPE, data->packet_type);
> 
>      if (OVS_UNLIKELY(parms->probe)) {
>          max_vlans = FLOW_MAX_VLAN_HEADERS;
> diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
> index 2e4942262ea0..8e2448b20dbd 100644
> --- a/lib/ofp-parse.c
> +++ b/lib/ofp-parse.c
> @@ -251,6 +251,7 @@ parse_field(const struct mf_field *mf, const char *s,
>      error = mf_parse(mf, s, port_map, &value, &mask);
>      if (!error) {
>          *usable_protocols &= mf_set(mf, &value, &mask, match, &error);
> +        match_add_ethernet_prereq(match, mf);
>      }
>      return error;
>  }
> @@ -297,6 +298,8 @@ parse_subfield(const char *name, const char *str_value, struct match *match,
>          bitwise_copy(&val, size, 0, &value, size, sf.ofs, sf.n_bits);
>          bitwise_one (               &mask,  size, sf.ofs, sf.n_bits);
>          *usable_protocols &= mf_set(field, &value, &mask, match, &error);
> +
> +        match_add_ethernet_prereq(match, sf.field);
>      }
>      return error;
>  }
> @@ -416,6 +419,9 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
>              if (p->nw_proto) {
>                  match_set_nw_proto(&fm->match, p->nw_proto);
>              }
> +            match_set_default_packet_type(&fm->match);
> +        } else if (!strcmp(name, "eth")) {
> +            match_set_packet_type(&fm->match, htonl(PT_ETH));
>          } else if (fields & F_FLAGS && !strcmp(name, "send_flow_rem")) {
>              fm->flags |= OFPUTIL_FF_SEND_FLOW_REM;
>          } else if (fields & F_FLAGS && !strcmp(name, "check_overlap")) {
> @@ -517,6 +523,12 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
>              return error;
>          }
>      }
> +    /* Copy ethertype to flow->dl_type for matches on packet_type
> +     * (OFPHTN_ETHERTYPE, ethertype). */
> +    if (fm->match.wc.masks.packet_type == OVS_BE32_MAX &&
> +            pt_ns(fm->match.flow.packet_type) == OFPHTN_ETHERTYPE) {
> +        fm->match.flow.dl_type = pt_ns_type_be(fm->match.flow.packet_type);
> +    }
>      /* Check for usable protocol interdependencies between match fields. */
>      if (fm->match.flow.dl_type == htons(ETH_TYPE_IPV6)) {
>          const struct flow_wildcards *wc = &fm->match.wc;
> diff --git a/lib/ofp-util.c b/lib/ofp-util.c
> index da171cdf6fe5..344b66a30d0c 100644
> --- a/lib/ofp-util.c
> +++ b/lib/ofp-util.c
> @@ -161,6 +161,19 @@ ofputil_match_from_ofp10_match(const struct ofp10_match *ofmatch,
>      ofputil_wildcard_from_ofpfw10(ofpfw, &match->wc);
>      memset(&match->tun_md, 0, sizeof match->tun_md);
> 
> +    /* If any fields, except in_port, are matched, then we also need to match
> +     * on the Ethernet packet_type. */
> +    const uint32_t ofpfw_data_bits = (OFPFW10_NW_TOS | OFPFW10_NW_PROTO
> +                                      | OFPFW10_TP_SRC | OFPFW10_TP_DST
> +                                      | OFPFW10_DL_SRC | OFPFW10_DL_DST
> +                                      | OFPFW10_DL_TYPE
> +                                      | OFPFW10_DL_VLAN | OFPFW10_DL_VLAN_PCP);
> +    if ((ofpfw & ofpfw_data_bits) != ofpfw_data_bits
> +        || ofputil_wcbits_to_netmask(ofpfw >> OFPFW10_NW_SRC_SHIFT)
> +        || ofputil_wcbits_to_netmask(ofpfw >> OFPFW10_NW_DST_SHIFT)) {
> +        match_set_default_packet_type(match);
> +    }
> +
>      /* Initialize most of match->flow. */
>      match->flow.nw_src = ofmatch->nw_src;
>      match->flow.nw_dst = ofmatch->nw_dst;
> @@ -328,6 +341,7 @@ ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch,
>      bool ipv4, arp, rarp;
> 
>      match_init_catchall(match);
> +    match->flow.tunnel.metadata.tab = NULL;
> 
>      if (!(wc & OFPFW11_IN_PORT)) {
>          ofp_port_t ofp_port;
> @@ -340,10 +354,13 @@ ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch,
>          match_set_in_port(match, ofp_port);
>      }
> 
> -    match_set_dl_src_masked(match, ofmatch->dl_src,
> -                            eth_addr_invert(ofmatch->dl_src_mask));
> -    match_set_dl_dst_masked(match, ofmatch->dl_dst,
> -                            eth_addr_invert(ofmatch->dl_dst_mask));
> +    struct eth_addr dl_src_mask = eth_addr_invert(ofmatch->dl_src_mask);
> +    struct eth_addr dl_dst_mask = eth_addr_invert(ofmatch->dl_dst_mask);
> +    if (!eth_addr_is_zero(dl_src_mask) || !eth_addr_is_zero(dl_dst_mask)) {
> +        match_set_dl_src_masked(match, ofmatch->dl_src, dl_src_mask);
> +        match_set_dl_dst_masked(match, ofmatch->dl_dst, dl_dst_mask);
> +        match_set_default_packet_type(match);
> +    }
> 
>      if (!(wc & OFPFW11_DL_VLAN)) {
>          if (ofmatch->dl_vlan == htons(OFPVID11_NONE)) {
> @@ -375,11 +392,13 @@ ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch,
>                  }
>              }
>          }
> +        match_set_default_packet_type(match);
>      }
> 
>      if (!(wc & OFPFW11_DL_TYPE)) {
>          match_set_dl_type(match,
>                            ofputil_dl_type_from_openflow(ofmatch->dl_type));
> +        match_set_default_packet_type(match);
>      }
> 
>      ipv4 = match->flow.dl_type == htons(ETH_TYPE_IP);
> @@ -7680,21 +7699,35 @@ ofputil_normalize_match__(struct match *match, bool may_log)
>          MAY_IPV6        = 1 << 6, /* ipv6_src, ipv6_dst, ipv6_label */
>          MAY_ND_TARGET   = 1 << 7, /* nd_target */
>          MAY_MPLS        = 1 << 8, /* mpls label and tc */
> +        MAY_ETHER       = 1 << 9, /* dl_src, dl_dst */
>      } may_match;
> 
> -    struct flow_wildcards wc;
> +    struct flow_wildcards wc = match->wc;
> +    ovs_be16 dl_type;
> 
>      /* Figure out what fields may be matched. */
> -    if (match->flow.dl_type == htons(ETH_TYPE_IP)) {
> -        may_match = MAY_NW_PROTO | MAY_IPVx | MAY_NW_ADDR;
> +    /* Check the packet_type first and extract dl_type. */
> +    if (wc.masks.packet_type == 0 || match_has_default_packet_type(match)) {
> +        may_match = MAY_ETHER;
> +        dl_type = match->flow.dl_type;
> +    } else if (wc.masks.packet_type == OVS_BE32_MAX &&
> +               pt_ns(match->flow.packet_type) == OFPHTN_ETHERTYPE) {
> +        may_match = 0;
> +        dl_type = pt_ns_type_be(match->flow.packet_type);
> +    } else {
> +        may_match = 0;
> +        dl_type = 0;
> +    }
> +    if (dl_type == htons(ETH_TYPE_IP)) {
> +        may_match |= MAY_NW_PROTO | MAY_IPVx | MAY_NW_ADDR;
>          if (match->flow.nw_proto == IPPROTO_TCP ||
>              match->flow.nw_proto == IPPROTO_UDP ||
>              match->flow.nw_proto == IPPROTO_SCTP ||
>              match->flow.nw_proto == IPPROTO_ICMP) {
>              may_match |= MAY_TP_ADDR;
>          }
> -    } else if (match->flow.dl_type == htons(ETH_TYPE_IPV6)) {
> -        may_match = MAY_NW_PROTO | MAY_IPVx | MAY_IPV6;
> +    } else if (dl_type == htons(ETH_TYPE_IPV6)) {
> +        may_match |= MAY_NW_PROTO | MAY_IPVx | MAY_IPV6;
>          if (match->flow.nw_proto == IPPROTO_TCP ||
>              match->flow.nw_proto == IPPROTO_UDP ||
>              match->flow.nw_proto == IPPROTO_SCTP) {
> @@ -7707,17 +7740,17 @@ ofputil_normalize_match__(struct match *match, bool may_log)
>                  may_match |= MAY_ND_TARGET | MAY_ARP_THA;
>              }
>          }
> -    } else if (match->flow.dl_type == htons(ETH_TYPE_ARP) ||
> -               match->flow.dl_type == htons(ETH_TYPE_RARP)) {
> -        may_match = MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA;
> -    } else if (eth_type_mpls(match->flow.dl_type)) {
> -        may_match = MAY_MPLS;
> -    } else {
> -        may_match = 0;
> +    } else if (dl_type == htons(ETH_TYPE_ARP) ||
> +               dl_type == htons(ETH_TYPE_RARP)) {
> +        may_match |= MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA;
> +    } else if (eth_type_mpls(dl_type)) {
> +        may_match |= MAY_MPLS;
>      }
> 
>      /* Clear the fields that may not be matched. */
> -    wc = match->wc;
> +    if (!(may_match & MAY_ETHER)) {
> +        wc.masks.dl_src = wc.masks.dl_dst = eth_addr_zero;
> +    }
>      if (!(may_match & MAY_NW_ADDR)) {
>          wc.masks.nw_src = wc.masks.nw_dst = htonl(0);
>      }
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index 48c4bad4ac0b..c7a7a371d32b 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -6125,6 +6125,7 @@ xlate_wc_init(struct xlate_ctx *ctx)
>      flow_wildcards_init_catchall(ctx->wc);
> 
>      /* Some fields we consider to always be examined. */
> +    WC_MASK_FIELD(ctx->wc, packet_type);
>      WC_MASK_FIELD(ctx->wc, in_port);
>      WC_MASK_FIELD(ctx->wc, dl_type);
>      if (is_ip_any(&ctx->xin->flow)) {
> diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
> index e27a9fb75d08..fa99b3102862 100644
> --- a/ofproto/tunnel.c
> +++ b/ofproto/tunnel.c
> @@ -386,8 +386,6 @@ tnl_wc_init(struct flow *flow, struct flow_wildcards *wc)
>              && IP_ECN_is_ce(flow->tunnel.ip_tos)) {
>              wc->masks.nw_tos |= IP_ECN_MASK;
>          }
> -        /* Match on packet_type for tunneled packets.*/
> -        wc->masks.packet_type = OVS_BE32_MAX;
>      }
>  }
> 
> diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
> index 586a5b1c2240..a526b85165bc 100644
> --- a/tests/dpif-netdev.at
> +++ b/tests/dpif-netdev.at
> @@ -68,16 +68,16 @@ m4_define([DPIF_NETDEV_DUMMY_IFACE],
>     AT_CHECK([ovs-ofctl add-flow br1 action=normal])
>     ovs-appctl time/stop
>     ovs-appctl time/warp 5000
> -   AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
> -   AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
> +   AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
> +   AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0
> .3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>     ovs-appctl time/warp 100
>     sleep 1  # wait for forwarders process packets
> 
>     AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> -recirc_id(0),in_port(2),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> -recirc_id(0),in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> -recirc_id(0),in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
> +recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
> +recirc_id(0),in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
> +recirc_id(0),in_port(8),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
>  ])
> 
>     OVS_VSWITCHD_STOP
> @@ -95,28 +95,29 @@ m4_define([DPIF_NETDEV_MISS_FLOW_INSTALL],
>     AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
> 
>     AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> -   AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
> +   AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
> +   ovs-appctl ofproto/trace
> 'in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
>     sleep 1
> 
>     AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl
> -
> skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src
> =50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=
> no),icmp(type=8,code=0)
> +skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet
> _type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,pr
> oto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
>  ])
>     AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
>  ])
> 
>     # Now, the same again without megaflows.
>     AT_CHECK([ovs-appctl upcall/disable-megaflows], [0], [megaflows disabled
>  ])
> -   AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
> +   AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>     sleep 1
> 
>     AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl
> -
> skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src
> =50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=
> no),icmp(type=8,code=0)
> +skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet
> _type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,pr
> oto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
>  ])
>     AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> -skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-
> dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00
> :00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
> +skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-
> dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:0
> 0:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(ty
> pe=8,code=0), actions: <del>
>  ])
> 
>     OVS_VSWITCHD_STOP
> @@ -136,14 +137,14 @@ m4_define([DPIF_NETDEV_MISS_FLOW_DUMP],
>     AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
> 
>     AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> -   AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
> +   AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>     sleep 1
> 
>     AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl
> -
> skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src
> =50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=
> no),icmp(type=8,code=0)
> +skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet
> _type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,pr
> oto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
>  ])
>     AT_CHECK([filter_flow_dump < ovs-vswitchd.log | strip_xout], [0], [dnl
> -
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.
> 0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions: <del>
> +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_
> port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0
> .0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0,
> used:never, actions: <del>
>  ])
> 
>     # Now, the same again without megaflows.
> @@ -151,15 +152,15 @@ skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label
>  ])
>     AT_CHECK([ovs-appctl upcall/disable-ufid], [0], [Datapath dumping tersely using UFID disabled
>  ], [])
> -   AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
> +   AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>     sleep 1
> 
>     AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl
> -
> skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src
> =50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=
> no),icmp(type=8,code=0)
> +skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet
> _type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,pr
> oto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
>  ])
>     AT_CHECK([filter_flow_dump < ovs-vswitchd.log | strip_xout], [0], [dnl
> -
> skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),et
> h(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,
> frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
> -
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.
> 0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions: <del>
> +skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),p
> acket_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0
> .1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
> +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_
> port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0
> .0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0,
> used:never, actions: <del>
>  ])
> 
>     OVS_VSWITCHD_STOP
> @@ -201,16 +202,16 @@ type=drop rate=1 burst_size=2
>  ])
> 
>  ovs-appctl time/warp 5000
> -AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0
> .3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0
> .3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0
> .3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0
> .3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0
> .3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
>  sleep 1  # wait for forwarders process packets
> 
>  # Meter 1 is measuring packets, allowing one packet per second with
> @@ -230,16 +231,16 @@ meter:2 flow_count:1 packet_in_count:5 byte_in_count:300 duration:0.0s bands:
>  # Advance time by 1/2 second
>  ovs-appctl time/warp 500
> 
> -AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> -AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0
> .2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0
> .3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0
> .3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0
> .3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0
> .3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8
> 'in_port(8),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0
> .3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
>  sleep 1  # wait for forwarders process packets
> 
>  # Meter 1 is measuring packets, allowing one packet per second with
> @@ -258,10 +259,10 @@ meter:2 flow_count:1 packet_in_count:10 byte_in_count:600 duration:0.0s bands:
>  ])
> 
>  AT_CHECK([cat ovs-vswitchd.log | filter_flow_install | strip_xout_keep_actions], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), actions:meter(0),7
> -recirc_id(0),in_port(2),eth_type(0x0800),ipv4(frag=no), actions:8
> -recirc_id(0),in_port(7),eth_type(0x0800),ipv4(frag=no), actions:meter(1),1
> -recirc_id(0),in_port(8),eth_type(0x0800),ipv4(frag=no), actions:2
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:meter(0),7
> +recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:8
> +recirc_id(0),in_port(7),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:meter(1),1
> +recirc_id(0),in_port(8),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:2
>  ])
> 
>  OVS_VSWITCHD_STOP
> diff --git a/tests/odp.at b/tests/odp.at
> index e408c9f9b778..0e8cbedc130d 100644
> --- a/tests/odp.at
> +++ b/tests/odp.at
> @@ -94,6 +94,7 @@ dnl Some fields are always printed for this test, because wildcards aren't
>  dnl specified. We can skip these.
>  sed -i 's/\(skb_mark(0)\),\(ct\)/\1,ct_state(0),ct_zone(0),\2/' odp-out.txt
>  sed -i 's/\(skb_mark([[^)]]*)\),\(recirc\)/\1,ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),\2/' odp-out.txt
> +sed -i 's/\(in_port(1)\),\(eth\)/\1,packet_type(ns=0,id=0),\2/' odp-out.txt
> 
>  AT_CHECK_UNQUOTED([ovstest test-odp parse-keys < odp-in.txt], [0], [`cat odp-out.txt`
>  ])
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index e2228661fd09..e73bce80a9d9 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -43,12 +43,12 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:
>  ovs-appctl time/warp 200 100
>  sleep 1
>  AT_CHECK([grep 'in_port([[348]])' ovs-vswitchd.log | filter_flow_install | strip_xout], [0], [dnl
> -recirc_id(0),in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> -recirc_id(0),in_port(3),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> -recirc_id(0),in_port(4),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0d),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> -recirc_id(0),in_port(4),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0e),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> -recirc_id(0),in_port(4),eth(src=50:54:00:00:00:09,dst=ff:ff:ff:ff:ff:ff),eth_type(0x8035), actions: <del>
> -recirc_id(0),in_port(4),eth(src=50:54:00:00:00:0b,dst=ff:ff:ff:ff:ff:ff),eth_type(0x8035), actions: <del>
> +recirc_id(0),in_port(3),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
> +recirc_id(0),in_port(3),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
> +recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0d),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
> +recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0e),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
> +recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=ff:ff:ff:ff:ff:ff),eth_type(0x8035),
> actions: <del>
> +recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=ff:ff:ff:ff:ff:ff),eth_type(0x8035),
> actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -477,9 +477,9 @@ done
> 
>  AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/dp_hash(.*\/0x1)/dp_hash(0xXXXX\/0x1)/' | sed
> 's/packets.*actions:1/actions:1/' | strip_ufid | strip_used | sort], [0], [dnl
>  flow-dump from non-dpdk interfaces:
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(src=192.168.0.1,frag=no), packets:15, bytes:630, used:0.0s,
> actions:hash(hash_l4(0)),recirc(0x1)
> -recirc_id(0x1),dp_hash(0xXXXX/0x1),in_port(1),eth_type(0x0800),ipv4(frag=no), actions:10
> -recirc_id(0x1),dp_hash(0xXXXX/0x1),in_port(1),eth_type(0x0800),ipv4(frag=no), actions:11
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=192.168.0.1,frag=no), packets:15,
> bytes:630, used:0.0s, actions:hash(hash_l4(0)),recirc(0x1)
> +recirc_id(0x1),dp_hash(0xXXXX/0x1),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:10
> +recirc_id(0x1),dp_hash(0xXXXX/0x1),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:11
>  ])
> 
>  AT_CHECK([ovs-appctl revalidator/purge], [0])
> @@ -493,8 +493,8 @@ done
> 
>  AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/dp_hash(.*\/0x1)/dp_hash(0xXXXX\/0x1)/' | strip_ufid | strip_used |
> sort], [0], [dnl
>  flow-dump from non-dpdk interfaces:
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(src=192.168.0.1,frag=no), packets:15, bytes:630, used:0.0s,
> actions:hash(hash_l4(0)),recirc(0x2)
> -recirc_id(0x2),dp_hash(0xXXXX/0x1),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:15, bytes:630, used:0.0s,
> actions:11
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=192.168.0.1,frag=no), packets:15,
> bytes:630, used:0.0s, actions:hash(hash_l4(0)),recirc(0x2)
> +recirc_id(0x2),dp_hash(0xXXXX/0x1),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:15,
> bytes:630, used:0.0s, actions:11
>  ])
> 
>  OVS_VSWITCHD_STOP
> @@ -4030,9 +4030,9 @@ done
> 
>  AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [dnl
>  flow-dump from non-dpdk interfaces:
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(dst=80), packets:0, bytes:0, used:never,
> actions:set(tcp(dst=81)),1
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=first),tcp(dst=80), packets:0, bytes:0, used:never,
> actions:set(tcp(dst=81)),5
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=later), packets:0, bytes:0, used:never, actions:6
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(dst=80), packets:0,
> bytes:0, used:never, actions:set(tcp(dst=81)),1
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=first),tcp(dst=80), packets:0,
> bytes:0, used:never, actions:set(tcp(dst=81)),5
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=later), packets:0, bytes:0,
> used:never, actions:6
>  ])
> 
>  mode=drop
> @@ -4048,9 +4048,9 @@ done
> 
>  AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [dnl
>  flow-dump from non-dpdk interfaces:
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(dst=80), packets:0, bytes:0, used:never,
> actions:set(tcp(dst=81)),1
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(frag=first), packets:0, bytes:0, used:never, actions:drop
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(frag=later), packets:0, bytes:0, used:never, actions:drop
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(dst=80), packets:0,
> bytes:0, used:never, actions:set(tcp(dst=81)),1
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=first), packets:0, bytes:0, used:never,
> actions:drop
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=later), packets:0, bytes:0, used:never,
> actions:drop
>  ])
> 
>  mode=nx-match
> @@ -4066,9 +4066,9 @@ done
> 
>  AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [dnl
>  flow-dump from non-dpdk interfaces:
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(dst=80), packets:0, bytes:0, used:never,
> actions:set(tcp(dst=81)),1
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=first),tcp(dst=80), packets:0, bytes:0, used:never,
> actions:set(tcp(dst=81)),2
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=later), packets:0, bytes:0, used:never, actions:6
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(dst=80), packets:0,
> bytes:0, used:never, actions:set(tcp(dst=81)),1
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=first),tcp(dst=80), packets:0,
> bytes:0, used:never, actions:set(tcp(dst=81)),2
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=later), packets:0, bytes:0,
> used:never, actions:6
>  ])
> 
>  OVS_VSWITCHD_STOP
> @@ -4141,9 +4141,9 @@ dnl wildcard and the set_field action have a mask of 0xFF. Up to (including)
>  dnl OVS-2.5, the wildcards and set_field mask are shared internally.
>  AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/used:[[0-9]].[[0-9]]*s/used:0.001s/'], [0], [dnl
>  flow-dump from non-dpdk interfaces:
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(src=33419/0xff), packets:0, bytes:0,
> used:never, actions:set(tcp(src=42/0xff)),1
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=first),tcp(src=33419/0xff), packets:0, bytes:0,
> used:never, actions:set(tcp(src=42/0xff)),1
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=later), packets:1, bytes:74, used:0.001s, actions:1
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(src=33419/0xff),
> packets:0, bytes:0, used:never, actions:set(tcp(src=42/0xff)),1
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=first),tcp(src=33419/0xff),
> packets:0, bytes:0, used:never, actions:set(tcp(src=42/0xff)),1
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=later), packets:1, bytes:74,
> used:0.001s, actions:1
>  ])
> 
>  AT_CHECK([ovs-appctl revalidator/purge], [0])
> @@ -4156,9 +4156,9 @@ done
> 
>  AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/used:[[0-9]].[[0-9]]*s/used:0.001s/'], [0], [dnl
>  flow-dump from non-dpdk interfaces:
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(src=0/0xff), packets:0, bytes:0, used:never,
> actions:set(tcp(src=42/0xff)),1
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=first),tcp(src=0/0xff), packets:0, bytes:0, used:never,
> actions:set(tcp(src=42/0xff)),1
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=later), packets:1, bytes:38, used:0.001s, actions:1
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(src=0/0xff), packets:0,
> bytes:0, used:never, actions:set(tcp(src=42/0xff)),1
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=first),tcp(src=0/0xff),
> packets:0, bytes:0, used:never, actions:set(tcp(src=42/0xff)),1
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=later), packets:1, bytes:38,
> used:0.001s, actions:1
>  ])
> 
>  AT_CHECK([ovs-appctl revalidator/purge], [0])
> @@ -4171,9 +4171,9 @@ done
> 
>  AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/used:[[0-9]].[[0-9]]*s/used:0.001s/'], [0], [dnl
>  flow-dump from non-dpdk interfaces:
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(src=0/0xff), packets:0, bytes:0, used:never,
> actions:set(tcp(src=42/0xff)),1
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=first),tcp(src=0/0xff), packets:0, bytes:0, used:never,
> actions:set(tcp(src=42/0xff)),1
> -recirc_id(0),in_port(90),eth_type(0x0800),ipv4(proto=6,frag=later), packets:1, bytes:34, used:0.001s, actions:1
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(src=0/0xff), packets:0,
> bytes:0, used:never, actions:set(tcp(src=42/0xff)),1
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=first),tcp(src=0/0xff),
> packets:0, bytes:0, used:never, actions:set(tcp(src=42/0xff)),1
> +recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=later), packets:1, bytes:34,
> used:0.001s, actions:1
>  ])
> 
>  OVS_VSWITCHD_STOP
> @@ -7203,21 +7203,21 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p3
> 'in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  ovs-appctl revalidator/wait
>  AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
> -recirc_id(0),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never,
> actions:drop
> +recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never,
> actions:drop
>  ])
> 
>  AT_CHECK([ovs-appctl dpif/dump-flows br1 | strip_ufid | strip_used | sort], [0], [dnl
> -recirc_id(0),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
> +recirc_id(0),in_port(3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never,
> actions:drop
>  ])
> 
>  AT_CHECK([ovs-appctl dpif/dump-flows -m br0 | strip_ufid | strip_used | sort], [0], [dnl
> -
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(p1),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(s
> rc=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0),
> packets:0, bytes:0, used:never, actions:drop
> -
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(p2),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(s
> rc=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=0/0,code=0/0),
> packets:0, bytes:0, used:never, actions:drop
> +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_
> port(p1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00)
> ,eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type
> =8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
> +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_
> port(p2),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00)
> ,eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type
> =0/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
>  ])
> 
>  AT_CHECK([ovs-appctl dpif/dump-flows -m br1 | strip_ufid | strip_used | sort], [0], [dnl
> -
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(p3),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(s
> rc=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0,
> bytes:0, used:never, actions:drop
> +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_
> port(p3),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00)
> ,eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,c
> ode=0/0), packets:0, bytes:0, used:never, actions:drop
>  ])
> 
>  OVS_VSWITCHD_STOP
> @@ -7240,7 +7240,7 @@ m4_define([OFPROTO_DPIF_GET_FLOW],
> 
>     UFID=`sed -n 's/\(ufid:[[-0-9a-fA-F]]*\).*/\1/p' stdout`
>     AT_CHECK([ovs-appctl dpctl/get-flow $UFID], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never,
> actions:drop
>  ])
> 
>     OVS_VSWITCHD_STOP
> @@ -7277,8 +7277,8 @@ for dl_src in 00 01; do
>  done
>  sleep 1  # wait for the datapath flow installed
>  AT_CHECK_UNQUOTED([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
> -
> recirc_id(0),in_port(1),eth(src=60:66:66:66:66:00),eth_type(0x8847),mpls(label=20,tc=0,ttl=32,bos=0,label=20,tc=0,tt
> l=32,bos=1), actions:userspace(pid=0,slow_path(controller))
> -
> recirc_id(0),in_port(1),eth(src=60:66:66:66:66:01),eth_type(0x8847),mpls(label=20/0x0,tc=0/0,ttl=32/0x0,bos=0/1,labe
> l=20/0xfffff,tc=0/7,ttl=32/0xff,bos=1/1), actions:userspace(pid=0,slow_path(controller))
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=60:66:66:66:66:00),eth_type(0x8847),mpls(label=20,tc=0,ttl=3
> 2,bos=0,label=20,tc=0,ttl=32,bos=1), actions:userspace(pid=0,slow_path(controller))
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=60:66:66:66:66:01),eth_type(0x8847),mpls(label=20/0x0,tc=0/0
> ,ttl=32/0x0,bos=0/1,label=20/0xfffff,tc=0/7,ttl=32/0xff,bos=1/1), actions:userspace(pid=0,slow_path(controller))
>  ])
> 
>  OVS_VSWITCHD_STOP
> @@ -7316,8 +7316,8 @@ for dl_src in 00 01; do
>  done
>  sleep 1  # wait for the datapath flow installed
>  AT_CHECK_UNQUOTED([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
> -
> recirc_id(0),in_port(1),eth(src=60:66:66:66:66:00),eth_type(0x8847),mpls(label=20,tc=0,ttl=32,bos=0,label=20,tc=0,tt
> l=32,bos=1), actions:userspace(pid=0,slow_path(controller))
> -
> recirc_id(0),in_port(1),eth(src=60:66:66:66:66:01),eth_type(0x8847),mpls(label=20/0x0,tc=0/0,ttl=32/0x0,bos=0/1,labe
> l=20/0xfffff,tc=0/7,ttl=32/0xff,bos=1/1), actions:userspace(pid=0,slow_path(controller))
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=60:66:66:66:66:00),eth_type(0x8847),mpls(label=20,tc=0,ttl=3
> 2,bos=0,label=20,tc=0,ttl=32,bos=1), actions:userspace(pid=0,slow_path(controller))
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=60:66:66:66:66:01),eth_type(0x8847),mpls(label=20/0x0,tc=0/0
> ,ttl=32/0x0,bos=0/1,label=20/0xfffff,tc=0/7,ttl=32/0xff,bos=1/1), actions:userspace(pid=0,slow_path(controller))
>  ])
> 
>  OVS_VSWITCHD_STOP
> @@ -7372,15 +7372,15 @@ dummy@ovs-dummy: hit:13 missed:2
>  ])
> 
>  AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
> -recirc_id(0),in_port(100),eth_type(0x0800),ipv4(frag=no), actions:101,3,2
> -recirc_id(0),in_port(101),eth_type(0x0800),ipv4(frag=no), actions:100,2,3
> +recirc_id(0),in_port(100),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:101,3,2
> +recirc_id(0),in_port(101),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:100,2,3
>  ])
> 
>  AT_CHECK([grep -e 'in_port(100).*packets:9' ovs-vswitchd.log | strip_ufid | filter_flow_dump], [0], [dnl
> -
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(100),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(
> src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0),
> packets:9, bytes:378, used:0.0s, actions:101,3,2
> +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_
> port(100),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00
> ),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(typ
> e=8/0,code=0/0), packets:9, bytes:378, used:0.0s, actions:101,3,2
>  ])
>  AT_CHECK([grep -e 'in_port(101).*packets:4' ovs-vswitchd.log | strip_ufid | filter_flow_dump], [0], [dnl
> -
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(101),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(
> src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0),
> packets:4, bytes:168, used:0.0s, actions:100,2,3
> +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_
> port(101),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00
> ),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(typ
> e=8/0,code=0/0), packets:4, bytes:168, used:0.0s, actions:100,2,3
>  ])
> 
>  AT_CHECK([ovs-ofctl dump-ports br0 pbr0], [0], [dnl
> @@ -7437,7 +7437,7 @@ dummy@ovs-dummy: hit:0 missed:1
>  ])
> 
>  AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
> -recirc_id(0),in_port(100),eth_type(0x0800),ipv4(src=192.168.0.1,frag=no),
> actions:101,set(ipv4(src=255.255.255.254)),2
> +recirc_id(0),in_port(100),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=192.168.0.1,frag=no),
> actions:101,set(ipv4(src=255.255.255.254)),2
>  ])
> 
>  AT_CHECK([grep -e '|ofproto_dpif_xlate|WARN|' ovs-vswitchd.log | sed "s/^.*|WARN|//"], [0], [dnl
> @@ -7480,7 +7480,7 @@ sleep 1
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7497,8 +7497,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09),eth_type(0x0800),ipv4(frag=no), actions: <del>
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:0b),eth_type(0x0800),ipv4(frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7516,8 +7516,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.252,frag=no), actions: <del>
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.4,proto=1,frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.252,frag=no),
> actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=10.0.0.4,proto=1,frag=no), actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7535,8 +7535,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x86dd),ipv6(src=2001:db8:3c4d:5:4:3:2:1,dst=2
> 001:db8:3c4d:1:2:3:4:1,label=0,proto=99,tclass=0x70,hlimit=64,frag=no)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x86dd),ipv6(src=2001:db8:3c4d:1:2:3:4:5,frag=no), actions: <del>
> -recirc_id(0),in_port(1),eth_type(0x86dd),ipv6(src=2001:db8:3c4d:5:4:3:2:1/ffff:ffff:ffff:fffc::,frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(src=2001:db8:3c4d:1:2:3:4:5,frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(src=2001:db8:3c4d:5:4:3:2:1/ffff:ffff:ffff:fff
> c::,frag=no), actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7554,7 +7554,7 @@ sleep 1
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(proto=1,frag=no),icmp(type=8), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=1,frag=no),icmp(type=8), actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7570,8 +7570,8 @@ m4_define([OFPROTO_DPIF_MEGAFLOW_NORMAL],
>     AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>     sleep 1
>     AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
>  ])
>     OVS_VSWITCHD_STOP
>     AT_CLEANUP])
> @@ -7592,8 +7592,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0a),eth_type(0x8847),mpls(label=11,tc=3,ttl=64,bos=1)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout_keep_actions], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09),eth_type(0x8847),mpls(label=11,tc=3,ttl=64,bos=1),
> actions:push_mpls(label=11,tc=3,ttl=64,bos=0,eth_type=0x8847),2
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:0b),eth_type(0x8847),mpls(label=11/0x0,tc=3/0,ttl=64/0x0,bos=1/1),
> actions:pop_mpls(eth_type=0x800),2
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09),eth_type(0x8847),mpls(label=11,tc=3,ttl=6
> 4,bos=1), actions:push_mpls(label=11,tc=3,ttl=64,bos=0,eth_type=0x8847),2
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b),eth_type(0x8847),mpls(label=11/0x0,tc=3/0
> ,ttl=64/0x0,bos=1/1), actions:pop_mpls(eth_type=0x800),2
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7619,8 +7619,8 @@ m4_define([CHECK_MEGAFLOW_NETFLOW],
>    AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>    sleep 1
>    AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -
> recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0
> .0.1,proto=1,tos=0/0xfc,frag=no),icmp(type=8,code=0), actions: <del>
> -
> recirc_id(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0
> .0.3,proto=1,tos=0/0xfc,frag=no),icmp(type=8,code=0), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ip
> v4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0/0xfc,frag=no),icmp(type=8,code=0), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ip
> v4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0/0xfc,frag=no),icmp(type=8,code=0), actions: <del>
>  ])
>    OVS_APP_EXIT_AND_WAIT([test-netflow])
>    OVS_VSWITCHD_STOP])
> @@ -7651,8 +7651,8 @@ m4_define([OFPROTO_DPIF_MEGAFLOW_NORMAL_ACB_BOND],
>     AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>     sleep 1
>     AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
>  ])
>     OVS_VSWITCHD_STOP
>     AT_CLEANUP])
> @@ -7675,8 +7675,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7713,8 +7713,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(1),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p7
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> -recirc_id(0),in_port(7),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> +recirc_id(0),in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
> +recirc_id(0),in_port(7),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7732,8 +7732,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09),eth_type(0x0800),ipv4(frag=no), actions: <del>
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:0b),eth_type(0x0800),ipv4(frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7752,8 +7752,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
>  1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09),eth_type(0x0800),ipv4(frag=no), actions: <del>
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:0b),eth_type(0x0800),ipv4(frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7771,8 +7771,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09),eth_type(0x0800),ipv4(frag=no), actions: <del>
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:0b),eth_type(0x0800),ipv4(frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7796,7 +7796,7 @@ sleep 1
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7818,8 +7818,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), actions: <del>
> -recirc_id(0),in_port(1),eth_type(0x8100),vlan(vid=11,pcp=7/0x0),encap(eth_type(0x0800),ipv4(frag=no)), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=11,pcp=7/0x0),encap(eth_type(0x0800),ipv4(
> frag=no)), actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7838,8 +7838,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2,frag=no), actions: <del>
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.4,frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=10.0.0.2,frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=10.0.0.4,frag=no), actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7856,8 +7856,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2,frag=no), actions: <del>
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.4,frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=10.0.0.2,frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=10.0.0.4,frag=no), actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7883,8 +7883,8 @@ done
>  sleep 1
>  dnl The original flow is missing due to a revalidation.
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09),eth_type(0x0800),ipv4(frag=no), actions: <del>
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:0b),eth_type(0x0800),ipv4(frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7915,9 +7915,9 @@ sleep 1
>  AT_CHECK([ovs-appctl netdev-dummy/receive p3
> 'in_port(3),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0x1,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(tos=0xfd/0x3,frag=no), actions: <del>
> -recirc_id(0),in_port(3),eth_type(0x0800),ipv4(tos=0x1,ttl=64,frag=no), actions: <del>
> -recirc_id(0),in_port(3),eth_type(0x0800),ipv4(tos=0xfd,ttl=128,frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0xfd/0x3,frag=no), actions: <del>
> +recirc_id(0),in_port(3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0x1,ttl=64,frag=no), actions: <del>
> +recirc_id(0),in_port(3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0xfd,ttl=128,frag=no), actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7935,8 +7935,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1
> ,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
>  sleep 1
>  AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.252,frag=no), actions: <del>
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.4,proto=1,ttl=64,frag=no), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.252,frag=no),
> actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=10.0.0.4,proto=1,ttl=64,frag=no), actions:
> <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7956,8 +7956,8 @@ dnl The first packet is essentially a no-op, as the new destination MAC is the
>  dnl same as the original.  The second entry actually updates the destination
>  dnl MAC.
>  AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
> -recirc_id(0),in_port(1),eth(dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions:2
> -recirc_id(0),in_port(1),eth(dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(frag=no),
> actions:set(eth(dst=50:54:00:00:00:0a)),2
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions:2
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(frag=no),
> actions:set(eth(dst=50:54:00:00:00:0a)),2
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -7987,12 +7987,12 @@ table=0 in_port=1,ip,nw_dst=10.0.0.3 actions=drop
>     done
>     sleep 1
>     AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
> -skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-
> dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00
> :00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:2
> -skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-
> dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00
> :00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0),
> actions:drop
> +skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-
> dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:0
> 0:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(ty
> pe=8,code=0), actions:2
> +skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-
> dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:0
> 0:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(ty
> pe=8,code=0), actions:drop
>  ])
>     AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_dump | grep 'packets:3'], [0], [dnl
> -
> skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),et
> h(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,
> frag=no),icmp(type=8,code=0), packets:3, bytes:126, used:0.0s, actions:2
> -
> skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),et
> h(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,
> frag=no),icmp(type=8,code=0), packets:3, bytes:126, used:0.0s, actions:drop
> +skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),p
> acket_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0
> .1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:126, used:0.0s, actions:2
> +skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),p
> acket_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0
> .3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:126, used:0.0s, actions:drop
>  ])
>     OVS_VSWITCHD_STOP
>     AT_CLEANUP])
> @@ -8561,8 +8561,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'recirc_id(0),in_port(1),eth(src=f2
>  AT_CHECK([ovs-appctl revalidator/purge], [0])
> 
>  AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x86dd),ipv6(proto=58,frag=no),icmpv6(type=128), actions:2
> -recirc_id(0),in_port(1),eth_type(0x86dd),ipv6(proto=58,frag=no),icmpv6(type=129), actions:3
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(proto=58,frag=no),icmpv6(type=128), actions:2
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(proto=58,frag=no),icmpv6(type=129), actions:3
>  ])
> 
>  AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
> @@ -8608,7 +8608,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p0 'in_port(1),eth(src=50:54:00:00:00:
> 
>  OVS_WAIT_UNTIL([grep flow_add: ovs-vswitchd.log])
>  AT_CHECK([grep 'in_port([[1]])' ovs-vswitchd.log | filter_flow_install | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x8100),vlan(vid=10),encap(eth_type(0x0800),ipv4(frag=no)), actions: <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=10),encap(eth_type(0x0800),ipv4(frag=no)),
> actions: <del>
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -8636,7 +8636,7 @@ for i in 1 2; do
>  done
> 
>  AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x1234), packets:2, bytes:28, used:0.0s, actions:push_vlan(vid=3,pcp=0),100
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:2, bytes:28, used:0.0s,
> actions:push_vlan(vid=3,pcp=0),100
>  ])
> 
>  AT_CHECK([ovs-ofctl add-flow br0 priority=60000,in_port=1,actions=mod_vlan_vid:4,output:local])
> @@ -8649,11 +8649,11 @@ for i in 1 2 3; do
>  done
> 
>  AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x1234), packets:5, bytes:70, used:0.0s, actions:push_vlan(vid=4,pcp=0),100
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:5, bytes:70, used:0.0s,
> actions:push_vlan(vid=4,pcp=0),100
>  ])
> 
>  AT_CHECK([grep 'modify' ovs-vswitchd.log | strip_ufid ], [0], [dnl
> -dpif|DBG|dummy@ovs-dummy: put[[modify]]
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234),
> actions:push_vlan(vid=4,pcp=0),100
> +dpif|DBG|dummy@ovs-dummy: put[[modify]]
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),e
> th_type(0x1234), actions:push_vlan(vid=4,pcp=0),100
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -8681,7 +8681,7 @@ for i in 1 2; do
>  done
> 
>  AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x1234), packets:2, bytes:28, used:0.0s, actions:100
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:2, bytes:28, used:0.0s, actions:100
>  ])
> 
>  # Delete the flow.  Then check that the datapath flow is modified to
> @@ -8697,7 +8697,7 @@ for i in 1 2 3; do
>  done
> 
>  AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x1234), packets:5, bytes:70, used:0.0s, actions:drop
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:5, bytes:70, used:0.0s, actions:drop
>  ])
> 
>  # Add a flow that matches the non-presence of a vlan tag, and check
> @@ -8712,7 +8712,7 @@ for i in 1 2 3; do
>  done
> 
>  AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x1234), packets:8, bytes:112, used:0.0s, actions:100
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:8, bytes:112, used:0.0s, actions:100
>  ])
> 
>  # Check that VLAN packets will not hit the same datapath megaflow.
> @@ -8725,17 +8725,17 @@ for i in 1 2; do
>  done
> 
>  AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x1234), packets:8, bytes:112, used:0.0s, actions:100
> -recirc_id(0),in_port(1),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), packets:2, bytes:36,
> used:0.0s, actions:drop
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:8, bytes:112, used:0.0s, actions:100
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)),
> packets:2, bytes:36, used:0.0s, actions:drop
>  ])
> 
>  # Check that the new flow matches the CFI bit, while both vid and pcp
>  # are wildcarded.
>  AT_CHECK([grep '\(modify\)\|\(flow_add\)' ovs-vswitchd.log | strip_ufid ], [0], [dnl
> -dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),eth_type(0x1234), actions:100
> -dpif|DBG|dummy@ovs-dummy: put[[modify]]
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234)
> -dpif|DBG|dummy@ovs-dummy: put[[modify]]
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234),
> actions:100
> -dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)),
> actions:drop
> +dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), actions:100
> +dpif|DBG|dummy@ovs-dummy: put[[modify]]
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),e
> th_type(0x1234)
> +dpif|DBG|dummy@ovs-dummy: put[[modify]]
> skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_p
> ort(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),e
> th_type(0x1234), actions:100
> +dpif_netdev|DBG|flow_add:
> recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)),
> actions:drop
>  ])
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> @@ -9060,10 +9060,10 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:
> 
> 
>  AT_CHECK([cat ovs-vswitchd.log | strip_ufid | filter_flow_install], [0], [dnl
> -ct_state(+new-est+trk),recirc_id(0x1),in_port(2),eth_type(0x0800),ipv4(frag=no), actions:drop
> -ct_state(-new+est+trk),recirc_id(0x1),in_port(2),eth_type(0x0800),ipv4(proto=17,frag=no), actions:1
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(proto=17,frag=no), actions:ct(commit),2
> -recirc_id(0),in_port(2),eth_type(0x0800),ipv4(proto=17,frag=no), actions:ct,recirc(0x1)
> +ct_state(+new-est+trk),recirc_id(0x1),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
> actions:drop
> +ct_state(-new+est+trk),recirc_id(0x1),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no),
> actions:1
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no), actions:ct(commit),2
> +recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no), actions:ct,recirc(0x1)
>  ])
> 
>  OVS_VSWITCHD_STOP
> @@ -9469,9 +9469,9 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:
>  ovs-appctl revalidator/wait
> 
>  AT_CHECK([cat ovs-vswitchd.log | strip_ufid | filter_flow_install], [0], [dnl
> -ct_state(+rpl+trk),ct_label(0x1),recirc_id(0x1),in_port(2),eth_type(0x0800),ipv4(frag=no), actions:1
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(proto=17,frag=no),udp(src=1), actions:ct(commit,label=0x1),2
> -recirc_id(0),in_port(2),eth_type(0x0800),ipv4(frag=no), actions:ct,recirc(0x1)
> +ct_state(+rpl+trk),ct_label(0x1),recirc_id(0x1),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
> actions:1
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no),udp(src=1),
> actions:ct(commit,label=0x1),2
> +recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:ct,recirc(0x1)
>  ])
> 
>  OVS_VSWITCHD_STOP
> @@ -9495,7 +9495,7 @@ dnl Start a new connection from port 1.
>  AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.1.1.1,dst=10.1.1.2,proto=1
> 7,tos=0,ttl=64,frag=no),udp(src=1,dst=2)'])
> 
>  AT_CHECK([cat ovs-vswitchd.log | strip_ufid | filter_flow_install], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(proto=17,frag=no), actions:ct(commit)
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no), actions:ct(commit)
>  ])
> 
>  OVS_VSWITCHD_STOP
> @@ -9781,7 +9781,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'recirc_id(0),in_port(1),eth_type(0
>  ovs-appctl time/warp 5000
> 
>  AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
> -recirc_id(0),in_port(1),eth_type(0x0800),ipv4(proto=17,frag=later), actions:drop
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=later), actions:drop
>  ])
> 
>  dnl Change the flow table.  This will trigger revalidation of all the flows.
> diff --git a/tests/ofproto.at b/tests/ofproto.at
> index 76a33b6902aa..25aa00aff4a2 100644
> --- a/tests/ofproto.at
> +++ b/tests/ofproto.at
> @@ -2390,6 +2390,7 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4
>      matching:
>        dp_hash: arbitrary mask
>        recirc_id: exact match or wildcard
> +      packet_type: exact match or wildcard
>        conj_id: exact match or wildcard
>        tun_id: arbitrary mask
>        tun_src: arbitrary mask
> diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
> index 52eaf0320cd5..6d2ae1d26bea 100644
> --- a/tests/ovs-ofctl.at
> +++ b/tests/ovs-ofctl.at
> @@ -2107,7 +2107,7 @@ OXM_OF_VLAN_VID_W(0123/1123)
>  nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  OXM_OF_VLAN_VID(1123)
>  OXM_OF_VLAN_VID(1123)
> -<any>
> +OXM_OF_PACKET_TYPE(00000000)
>  OXM_OF_VLAN_VID_W(1103/1f0f)
>  OXM_OF_VLAN_VID_W(1103/1f0f), OXM_OF_VLAN_PCP(01)
>  OXM_OF_VLAN_VID_W(1000/1000)
> diff --git a/tests/pmd.at b/tests/pmd.at
> index 05755b3f7202..d041dce96d25 100644
> --- a/tests/pmd.at
> +++ b/tests/pmd.at
> @@ -191,10 +191,10 @@ for i in `seq 0 19`;
>  ovs-appctl time/warp 100
> 
>  AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl
> -
> skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src
> =50:54:00:00:00:77,dst=50:54:00:00:01:78),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=
> no),icmp(type=8,code=0)
> +skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet
> _type(ns=0,id=0),eth(src=50:54:00:00:00:77,dst=50:54:00:00:01:78),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,pr
> oto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
>  ])
>  AT_CHECK([cat ovs-vswitchd.log | filter_flow_install | strip_xout], [0], [dnl
> -recirc_id(0),in_port(1),eth(src=50:54:00:00:00:77,dst=50:54:00:00:01:78),eth_type(0x0800),ipv4(frag=no), actions:
> <del>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:77,dst=50:54:00:00:01:78),eth_type(0x0800),ip
> v4(frag=no), actions: <del>
>  ])
> 
>  AT_CHECK([ovs-appctl dpif-netdev/pmd-stats-show | sed SED_NUMA_CORE_PATTERN | sed '/cycles/d' | grep pmd -A 5],
> [0], [dnl
> @@ -303,8 +303,8 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> 
>  dnl Make sure that both flows have been installed
>  AT_CHECK([ovs-appctl dpctl/dump-flows | flow_dump_prepend_pmd], [0], [dnl
> -0 recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never,
> actions:userspace(pid=0,slow_path(controller))
> -1 recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never,
> actions:userspace(pid=0,slow_path(controller))
> +0 recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never,
> actions:userspace(pid=0,slow_path(controller))
> +1 recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never,
> actions:userspace(pid=0,slow_path(controller))
>  ])
> 
>  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at
> index cbeb5788550f..228a9af43573 100644
> --- a/tests/tunnel-push-pop-ipv6.at
> +++ b/tests/tunnel-push-pop-ipv6.at
> @@ -164,7 +164,7 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port  5'], [0], [dnl
>    port  5: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=?
>  ])
>  AT_CHECK([ovs-appctl dpif/dump-flows int-br | grep 'in_port(6081)'], [0], [dnl
> -
> tunnel(tun_id=0x7b,ipv6_src=2001:cafe::92,ipv6_dst=2001:cafe::88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class
> =0xffff,type=0,len=4}),flags(-df-csum+key)),recirc_id(0),in_port(6081),eth_type(0x0800),ipv4(frag=no), packets:0,
> bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
> +tunnel(tun_id=0x7b,ipv6_src=2001:cafe::92,ipv6_dst=2001:cafe::88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{clas
> s=0xffff,type=0,len=4}),flags(-df-
> csum+key)),recirc_id(0),in_port(6081),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0,
> used:never, actions:userspace(pid=0,slow_path(controller))
>  ])
> 
>  OVS_VSWITCHD_STOP
> diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
> index e3aecb45e9a5..5a2c423839db 100644
> --- a/tests/tunnel-push-pop.at
> +++ b/tests/tunnel-push-pop.at
> @@ -215,7 +215,7 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port  5'], [0], [dnl
>    port  5: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=?
>  ])
>  AT_CHECK([ovs-appctl dpif/dump-flows int-br | grep 'in_port(6081)'], [0], [dnl
> -
> tunnel(tun_id=0x7b,src=1.1.2.92,dst=1.1.2.88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4
> }),flags(-df-csum+key)),recirc_id(0),in_port(6081),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never,
> actions:userspace(pid=0,slow_path(controller))
> +tunnel(tun_id=0x7b,src=1.1.2.92,dst=1.1.2.88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=
> 4}),flags(-df-csum+key)),recirc_id(0),in_port(6081),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
> packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
>  ])
> 
>  OVS_VSWITCHD_STOP
> diff --git a/tests/tunnel.at b/tests/tunnel.at
> index 222fb8d1a603..447c7205f224 100644
> --- a/tests/tunnel.at
> +++ b/tests/tunnel.at
> @@ -82,28 +82,28 @@ AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
>  dnl Tunnel CE and encapsulated packet CE
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy
> 'tunnel(src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),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=6,tos=3,ttl=64,frag=no),tcp(src=8,dst=9)'], [0],
> [stdout])
>  AT_CHECK([tail -2 stdout], [0],
> -  [Megaflow: recirc_id=0,packet_type=(0,0),ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_flags=-df-
> csum-key,in_port=1,nw_ecn=3,nw_frag=no
> +  [Megaflow: recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_flags=-df-csum-
> key,in_port=1,nw_ecn=3,nw_frag=no
>  Datapath actions: 2
>  ])
> 
>  dnl Tunnel CE and encapsulated packet ECT(1)
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy
> 'tunnel(src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),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=6,tos=1,ttl=64,frag=no),tcp(src=8,dst=9)'], [0],
> [stdout])
>  AT_CHECK([tail -2 stdout], [0],
> -  [Megaflow: recirc_id=0,packet_type=(0,0),ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_flags=-df-
> csum-key,in_port=1,nw_ecn=1,nw_frag=no
> +  [Megaflow: recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_flags=-df-csum-
> key,in_port=1,nw_ecn=1,nw_frag=no
>  Datapath actions: set(ipv4(tos=0x3/0x3)),2
>  ])
> 
>  dnl Tunnel CE and encapsulated packet ECT(2)
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy
> 'tunnel(src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),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=6,tos=2,ttl=64,frag=no),tcp(src=8,dst=9)'], [0],
> [stdout])
>  AT_CHECK([tail -2 stdout], [0],
> -  [Megaflow: recirc_id=0,packet_type=(0,0),ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_flags=-df-
> csum-key,in_port=1,nw_ecn=2,nw_frag=no
> +  [Megaflow: recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_flags=-df-csum-
> key,in_port=1,nw_ecn=2,nw_frag=no
>  Datapath actions: set(ipv4(tos=0x3/0x3)),2
>  ])
> 
>  dnl Tunnel CE and encapsulated packet Non-ECT
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy
> 'tunnel(src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),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=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0],
> [stdout])
>  AT_CHECK([tail -2 stdout], [0],
> -  [Megaflow: recirc_id=0,packet_type=(0,0),ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_flags=-df-
> csum-key,in_port=1,nw_ecn=0,nw_frag=no
> +  [Megaflow: recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_flags=-df-csum-
> key,in_port=1,nw_ecn=0,nw_frag=no
>  Datapath actions: drop
>  ])
>  OVS_VSWITCHD_STOP(["/dropping tunnel packet marked ECN CE but is not ECN capable/d"])
> @@ -490,14 +490,14 @@ AT_CHECK([tail -1 stdout], [0],
>  dnl Option match
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy
> 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0xb}),flags(df|key)
> ),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0],
> [stdout])
>  AT_CHECK([tail -2 stdout], [0],
> -  [Megaflow: recirc_id=0,packet_type=(0,0),ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-
> csum+key,tun_metadata0=0xb/0xf,in_port=1,nw_frag=no
> +  [Megaflow: recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-
> csum+key,tun_metadata0=0xb/0xf,in_port=1,nw_frag=no
>  Datapath actions: 2
>  ])
> 
>  dnl Skip unknown option
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy
> 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0xb}{class=0xffff,t
> ype=2,len=4,0xc}),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type
> (0x0800),ipv4(frag=no)'], [0], [stdout])
>  AT_CHECK([tail -2 stdout], [0],
> -  [Megaflow: recirc_id=0,packet_type=(0,0),ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-
> csum+key,tun_metadata0=0xb/0xf,in_port=1,nw_frag=no
> +  [Megaflow: recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-
> csum+key,tun_metadata0=0xb/0xf,in_port=1,nw_frag=no
>  Datapath actions: 2
>  ])
> 
> @@ -531,7 +531,7 @@ AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=3,len=8}->tun_metadata3"
>  AT_CHECK([ovs-ofctl add-flow br0 tun_metadata3=0x1234567890abcdef,actions=2])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy
> 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=3,len=8,0x1234567890abcdef}
> ),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(fr
> ag=no)'], [0], [stdout])
>  AT_CHECK([tail -2 stdout], [0],
> -  [Megaflow: recirc_id=0,packet_type=(0,0),ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-
> csum+key,tun_metadata3=0x1234567890abcdef,in_port=1,nw_frag=no
> +  [Megaflow: recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-
> csum+key,tun_metadata3=0x1234567890abcdef,in_port=1,nw_frag=no
>  Datapath actions: 2
>  ])
> 
> @@ -640,13 +640,13 @@ NXST_FLOW reply:
> 
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy
> 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0x12345678}),flags(
> df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)']
> , [0], [stdout])
>  AT_CHECK([tail -2 stdout], [0],
> -  [Megaflow: recirc_id=0,packet_type=(0,0),ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-
> csum+key,tun_metadata0,tun_metadata1=NP,tun_metadata2=NP,in_port=1,nw_frag=no
> +  [Megaflow: recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-
> csum+key,tun_metadata0,tun_metadata1=NP,tun_metadata2=NP,in_port=1,nw_frag=no
>  Datapath actions: 2
>  ])
> 
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy
> 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=1,len=0}),flags(df|key)),in
> _port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0],
> [stdout])
>  AT_CHECK([tail -2 stdout], [0],
> -  [Megaflow: recirc_id=0,packet_type=(0,0),ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-
> csum+key,tun_metadata1,tun_metadata2=NP,in_port=1,nw_ecn=0,nw_frag=no
> +  [Megaflow: recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-
> csum+key,tun_metadata1,tun_metadata2=NP,in_port=1,nw_ecn=0,nw_frag=no
>  Datapath actions:
> set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,tp_dst=6081,geneve({class=0xffff,type=0x1,len=0}),flags(df|key))),6081
>  ])
> 
> --
> 2.10.2
> 
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Comments

Ben Pfaff June 20, 2017, 2:02 a.m. UTC | #1
On Mon, Jun 19, 2017 at 04:11:01PM +0000, Zoltán Balogh wrote:
> Hi Ben,
> 
> I've been testing L2/L3 tunneling and ptap ports receiving/transmitting L2 and L3 packets. 
> I observed, that 'ovs-appctl dpctl/dump-flows' prints out packet_type 'id' in decimal format.
> For instance, in case of receiving a L3 MPLS packet on a ptap port results in:
> 
> tunnel(src=20.0.0.1,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(7),packet_type(ns=1,id=34887),eth_type(0x8847), packets:24, bytes:2112, used:0.064s, actions:drop
> 
> Would not it be more readable, to use hex format if the 'id' is not zero?
> 
> By applying this diff:
> 
> diff --git a/lib/odp-util.c b/lib/odp-util.c
> index ef8651247..72f4f2324 100644
> --- a/lib/odp-util.c
> +++ b/lib/odp-util.c
> @@ -2992,7 +2992,10 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
>  
>          ovs_be16 ns_type = pt_ns_type_be(value);
>          ovs_be16 ns_type_mask = pt_ns_type_be(mask);
> -        format_be16(ds, "id", ns_type, &ns_type_mask, verbose);
> +        if (ns_type)
> +            format_be16x(ds, "id", ns_type, &ns_type_mask, verbose);
> +        else
> +            format_be16(ds, "id", ns_type, &ns_type_mask, verbose);
>  
>          ds_chomp(ds, ',');
>          break;
> 
> ... we can get printouts like this:
> 
> recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:9
> tunnel(src=20.0.0.1,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(7),packet_type(ns=1,id=0x8847),eth_type(0x8847), packets:0, bytes:0, used:never, actions:drop

Sure, that's a good idea.  I think we can make it unconditionally hex,
though.  There are only a few packet_types defined, and I think it's OK
to show all of them with hex as the ns_type.

I'll fold this into the next version.
diff mbox

Patch

diff --git a/lib/odp-util.c b/lib/odp-util.c
index ef8651247..72f4f2324 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -2992,7 +2992,10 @@  format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
 
         ovs_be16 ns_type = pt_ns_type_be(value);
         ovs_be16 ns_type_mask = pt_ns_type_be(mask);
-        format_be16(ds, "id", ns_type, &ns_type_mask, verbose);
+        if (ns_type)
+            format_be16x(ds, "id", ns_type, &ns_type_mask, verbose);
+        else
+            format_be16(ds, "id", ns_type, &ns_type_mask, verbose);
 
         ds_chomp(ds, ',');
         break;