From: Eli Britstein <[email protected]>

Introduce eth-type field to tunnel metadata that is internally matched
for tunnels, for robust detection of the IP type.

Signed-off-by: Eli Britstein <[email protected]>
---
 include/linux/openvswitch.h     |  1 +
 include/openvswitch/match.h     |  3 ++
 include/openvswitch/meta-flow.h | 14 +++++++
 include/openvswitch/packets.h   |  3 +-
 lib/flow.c                      |  3 ++
 lib/match.c                     | 17 ++++++++
 lib/meta-flow.c                 | 20 ++++++++++
 lib/meta-flow.xml               |  1 +
 lib/netdev-native-tnl.c         |  6 +++
 lib/netdev-offload-dpdk.c       |  3 ++
 lib/odp-util.c                  | 15 +++++++
 lib/odp-util.h                  |  5 ++-
 ofproto/ofproto-dpif-xlate.c    |  9 ++++-
 ofproto/ofproto-dpif.c          | 71 +++++++++++++++++++++++++++++++++
 ofproto/tunnel.c                |  1 +
 tests/nsh.at                    | 10 ++---
 tests/packet-type-aware.at      | 22 +++++-----
 tests/tunnel-push-pop-ipv6.at   |  2 +-
 tests/tunnel-push-pop.at        |  2 +-
 tests/tunnel.at                 | 44 ++++++++++++++++++++
 20 files changed, 231 insertions(+), 21 deletions(-)

diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index e69fed4b73ca..059f24858015 100644
--- a/include/linux/openvswitch.h
+++ b/include/linux/openvswitch.h
@@ -447,6 +447,7 @@ enum ovs_tunnel_key_attr {
 #ifndef __KERNEL__
        /* Only used within userspace data path. */
        OVS_TUNNEL_KEY_ATTR_GTPU_OPTS,          /* struct gtpu_metadata */
+       OVS_TUNNEL_KEY_ATTR_ETHERTYPE,          /* be16 Ethernet type */
 #endif
        __OVS_TUNNEL_KEY_ATTR_MAX
 };
diff --git a/include/openvswitch/match.h b/include/openvswitch/match.h
index 2e8812048e86..eea95743c8f7 100644
--- a/include/openvswitch/match.h
+++ b/include/openvswitch/match.h
@@ -127,6 +127,9 @@ void match_set_tun_gtpu_flags_masked(struct match *match, 
uint8_t flags,
 void match_set_tun_gtpu_msgtype(struct match *match, uint8_t msgtype);
 void match_set_tun_gtpu_msgtype_masked(struct match *match, uint8_t msgtype,
                                        uint8_t mask);
+void match_set_tun_eth_type(struct match *, ovs_be16 eth_type);
+void match_set_tun_eth_type_masked(struct match *match, ovs_be16 eth_type,
+                                   uint16_t mask);
 void match_set_in_port(struct match *, ofp_port_t ofp_port);
 void match_set_pkt_mark(struct match *, uint32_t pkt_mark);
 void match_set_pkt_mark_masked(struct match *, uint32_t pkt_mark, uint32_t 
mask);
diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
index 875f122c5f55..b964df917b2e 100644
--- a/include/openvswitch/meta-flow.h
+++ b/include/openvswitch/meta-flow.h
@@ -304,6 +304,20 @@ enum OVS_PACKED_ENUM mf_field_id {
      */
     MFF_TUN_ID,
 
+    /* "tun_eth_type".
+     *
+     * Packet's Tunnel Ethernet type.
+     *
+     * Type: be16.
+     * Maskable: no.
+     * Formatting: hexadecimal.
+     * Prerequisites: none.
+     * Access: read-only.
+     * NXM: none.
+     * OXM: none.
+     */
+    MFF_TUN_ETH_TYPE,
+
     /* "tun_src".
      *
      * The IPv4 source address in the outer IP header of a tunneled packet.
diff --git a/include/openvswitch/packets.h b/include/openvswitch/packets.h
index a65cb0d04e77..c9af1b6ceca6 100644
--- a/include/openvswitch/packets.h
+++ b/include/openvswitch/packets.h
@@ -45,7 +45,8 @@ struct flow_tnl {
     uint8_t erspan_hwid;
     uint8_t gtpu_flags;
     uint8_t gtpu_msgtype;
-    uint8_t pad1[4];     /* Pad to 64 bits. */
+    ovs_be16 eth_type;
+    uint8_t pad1[2];     /* Pad to 64 bits. */
     struct tun_metadata metadata;
 };
 
diff --git a/lib/flow.c b/lib/flow.c
index b522f7f116ca..05e8ae0a6206 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -1323,6 +1323,9 @@ flow_get_metadata(const struct flow *flow, struct match 
*flow_metadata)
         match_set_tun_flags(flow_metadata,
                             flow->tunnel.flags & FLOW_TNL_PUB_F_MASK);
     }
+    if (flow->tunnel.eth_type) {
+        match_set_tun_eth_type(flow_metadata, flow->tunnel.eth_type);
+    }
     if (flow->tunnel.ip_src) {
         match_set_tun_src(flow_metadata, flow->tunnel.ip_src);
     }
diff --git a/lib/match.c b/lib/match.c
index 9b7e06e0c7f8..20ece16a9d3f 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -402,6 +402,20 @@ match_set_tun_gtpu_msgtype(struct match *match, uint8_t 
msgtype)
     match_set_tun_gtpu_msgtype_masked(match, msgtype, UINT8_MAX);
 }
 
+void
+match_set_tun_eth_type_masked(struct match *match, ovs_be16 eth_type,
+                              uint16_t mask)
+{
+    match->wc.masks.tunnel.eth_type = eth_type;
+    match->flow.tunnel.eth_type = eth_type & mask;
+}
+
+void
+match_set_tun_eth_type(struct match *match, ovs_be16 eth_type)
+{
+    match_set_tun_eth_type_masked(match, eth_type, OVS_BE16_MAX);
+}
+
 void
 match_set_in_port(struct match *match, ofp_port_t ofp_port)
 {
@@ -1391,6 +1405,9 @@ format_flow_tunnel(struct ds *s, const struct match 
*match)
     if (wc->masks.tunnel.gtpu_msgtype) {
         ds_put_format(s, "gtpu_msgtype=%"PRIu8",", tnl->gtpu_msgtype);
     }
+    if (wc->masks.tunnel.eth_type) {
+        ds_put_format(s, "tun_eth_type=0x%04"PRIx16",", ntohs(tnl->eth_type));
+    }
     if (wc->masks.tunnel.flags & FLOW_TNL_F_MASK) {
         format_flags_masked(s, "tun_flags", flow_tun_flag_to_string,
                             tnl->flags & FLOW_TNL_F_MASK,
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 2595fd634b4d..1f33aeeccf6f 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -213,6 +213,8 @@ mf_is_all_wild(const struct mf_field *mf, const struct 
flow_wildcards *wc)
         return !wc->masks.packet_type;
     case MFF_CONJ_ID:
         return !wc->masks.conj_id;
+    case MFF_TUN_ETH_TYPE:
+        return !wc->masks.tunnel.eth_type;
     case MFF_TUN_SRC:
         return !wc->masks.tunnel.ip_src;
     case MFF_TUN_DST:
@@ -524,6 +526,7 @@ mf_is_value_valid(const struct mf_field *mf, const union 
mf_value *value)
     case MFF_PACKET_TYPE:
     case MFF_CONJ_ID:
     case MFF_TUN_ID:
+    case MFF_TUN_ETH_TYPE:
     case MFF_TUN_SRC:
     case MFF_TUN_DST:
     case MFF_TUN_IPV6_SRC:
@@ -680,6 +683,9 @@ mf_get_value(const struct mf_field *mf, const struct flow 
*flow,
     case MFF_TUN_ID:
         value->be64 = flow->tunnel.tun_id;
         break;
+    case MFF_TUN_ETH_TYPE:
+        value->be16 = flow->tunnel.eth_type;
+        break;
     case MFF_TUN_SRC:
         value->be32 = flow->tunnel.ip_src;
         break;
@@ -1017,6 +1023,9 @@ mf_set_value(const struct mf_field *mf,
     case MFF_TUN_ID:
         match_set_tun_id(match, value->be64);
         break;
+    case MFF_TUN_ETH_TYPE:
+        match_set_tun_eth_type(match, value->be16);
+        break;
     case MFF_TUN_SRC:
         match_set_tun_src(match, value->be32);
         break;
@@ -1439,6 +1448,9 @@ mf_set_flow_value(const struct mf_field *mf,
     case MFF_TUN_ID:
         flow->tunnel.tun_id = value->be64;
         break;
+    case MFF_TUN_ETH_TYPE:
+        flow->tunnel.eth_type = value->be16;
+        break;
     case MFF_TUN_SRC:
         flow->tunnel.ip_src = value->be32;
         break;
@@ -1823,6 +1835,7 @@ mf_is_any_metadata(const struct mf_field *mf)
         return true;
 
     case MFF_TUN_ID:
+    case MFF_TUN_ETH_TYPE:
     case MFF_TUN_SRC:
     case MFF_TUN_DST:
     case MFF_TUN_IPV6_SRC:
@@ -1917,6 +1930,7 @@ mf_is_pipeline_field(const struct mf_field *mf)
 {
     switch (mf->id) {
     case MFF_TUN_ID:
+    case MFF_TUN_ETH_TYPE:
     case MFF_TUN_SRC:
     case MFF_TUN_DST:
     case MFF_TUN_IPV6_SRC:
@@ -2075,6 +2089,9 @@ mf_set_wild(const struct mf_field *mf, struct match 
*match, char **err_str)
     case MFF_TUN_ID:
         match_set_tun_id_masked(match, htonll(0), htonll(0));
         break;
+    case MFF_TUN_ETH_TYPE:
+        match_set_tun_eth_type_masked(match, 0, 0);
+        break;
     case MFF_TUN_SRC:
         match_set_tun_src_masked(match, htonl(0), htonl(0));
         break;
@@ -2487,6 +2504,9 @@ mf_set(const struct mf_field *mf,
     case MFF_TUN_ID:
         match_set_tun_id_masked(match, value->be64, mask->be64);
         break;
+    case MFF_TUN_ETH_TYPE:
+        match_set_tun_eth_type_masked(match, value->be16, mask->be16);
+        break;
     case MFF_TUN_SRC:
         match_set_tun_src_masked(match, value->be32, mask->be32);
         break;
diff --git a/lib/meta-flow.xml b/lib/meta-flow.xml
index 5c57ab08ff18..558298279b9e 100644
--- a/lib/meta-flow.xml
+++ b/lib/meta-flow.xml
@@ -1508,6 +1508,7 @@ ovs-ofctl add-flow br-int 
'in_port=3,tun_src=192.168.1.1,tun_id=5001 actions=1'
       </diagram>
     </field>
 
+    <field id="MFF_TUN_ETH_TYPE" title="Tunnel Ethernet type" internal="yes"/>
     <field id="MFF_TUN_SRC" title="Tunnel IPv4 Source">
       <p>
         When a packet is received from a tunnel, this field is the
diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c
index 008b452b8a6e..47182d460a17 100644
--- a/lib/netdev-native-tnl.c
+++ b/lib/netdev-native-tnl.c
@@ -95,6 +95,7 @@ ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl 
*tnl,
     void *nh;
     struct ip_header *ip;
     struct ovs_16aligned_ip6_hdr *ip6;
+    const struct eth_header *eth;
     void *l4;
     int l3_size;
 
@@ -175,6 +176,11 @@ ip_extract_tnl_md(struct dp_packet *packet, struct 
flow_tnl *tnl,
         return NULL;
     }
 
+    eth = dp_packet_eth(packet);
+    if (eth) {
+        tnl->eth_type = eth->eth_type;
+    }
+
     return l4;
 }
 
diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index ca1982ccd8fb..766f03cd1f29 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -1253,6 +1253,9 @@ parse_tnl_ip_match(struct flow_patterns *patterns,
         return -1;
     }
 
+    /* Temporary ignore. */
+    match->wc.masks.tunnel.eth_type = 0;
+
     return 0;
 }
 
diff --git a/lib/odp-util.c b/lib/odp-util.c
index ee186820200b..108c9cf91681 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -2877,6 +2877,7 @@ static const struct attr_len_tbl 
ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX +
     [OVS_TUNNEL_KEY_ATTR_IPV6_DST]      = { .len = 16 },
     [OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS]   = { .len = ATTR_LEN_VARIABLE },
     [OVS_TUNNEL_KEY_ATTR_GTPU_OPTS]   = { .len = ATTR_LEN_VARIABLE },
+    [OVS_TUNNEL_KEY_ATTR_ETHERTYPE]     = { .len = 2 },
 };
 
 const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = {
@@ -3278,6 +3279,9 @@ odp_tun_key_from_attr__(const struct nlattr *attr, bool 
is_mask,
             tun->gtpu_msgtype = opts->msgtype;
             break;
         }
+        case OVS_TUNNEL_KEY_ATTR_ETHERTYPE:
+            tun->eth_type = nl_attr_get_be16(a);
+            break;
 
         default:
             /* Allow this to show up as unexpected, if there are unknown
@@ -3402,6 +3406,11 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl 
*tun_key,
         nl_msg_put_unspec(a, OVS_TUNNEL_KEY_ATTR_GTPU_OPTS,
                           &opts, sizeof(opts));
     }
+
+    if (tun_key->eth_type) {
+        nl_msg_put_be16(a, OVS_TUNNEL_KEY_ATTR_ETHERTYPE, tun_key->eth_type);
+    }
+
     nl_msg_end_nested(a, tun_key_ofs);
 }
 
@@ -4177,6 +4186,10 @@ format_odp_tun_attr(const struct nlattr *attr, const 
struct nlattr *mask_attr,
             format_odp_tun_gtpu_opt(a, ma, ds, verbose);
             ds_put_cstr(ds, "),");
             break;
+        case OVS_TUNNEL_KEY_ATTR_ETHERTYPE:
+            format_be16x(ds, "eth_type", nl_attr_get_be16(a),
+                         ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
         case __OVS_TUNNEL_KEY_ATTR_MAX:
         default:
             format_unknown_key(ds, a, ma);
@@ -6064,6 +6077,8 @@ parse_odp_key_mask_attr__(struct parse_odp_context 
*context, const char *s,
 
     SCAN_BEGIN_NESTED("tunnel(", OVS_KEY_ATTR_TUNNEL) {
         SCAN_FIELD_NESTED("tun_id=", ovs_be64, be64, OVS_TUNNEL_KEY_ATTR_ID);
+        SCAN_FIELD_NESTED("eth_type=", ovs_be16, be16,
+                          OVS_TUNNEL_KEY_ATTR_ETHERTYPE);
         SCAN_FIELD_NESTED("src=", ovs_be32, ipv4, 
OVS_TUNNEL_KEY_ATTR_IPV4_SRC);
         SCAN_FIELD_NESTED("dst=", ovs_be32, ipv4, 
OVS_TUNNEL_KEY_ATTR_IPV4_DST);
         SCAN_FIELD_NESTED("ipv6_src=", struct in6_addr, in6_addr, 
OVS_TUNNEL_KEY_ATTR_IPV6_SRC);
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 339ffc14f248..66b5339ed2ba 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -207,7 +207,10 @@ int odp_flow_from_string(const char *s, const struct simap 
*port_names,
                                                                              \
     /* If true, it means that the datapath supports the IPv6 Neigh           \
      * Discovery Extension bits. */                                          \
-    ODP_SUPPORT_FIELD(bool, nd_ext, "IPv6 ND Extension")
+    ODP_SUPPORT_FIELD(bool, nd_ext, "IPv6 ND Extension")                     \
+                                                                             \
+    /* Tunnel ethernet type matching supported. */                           \
+    ODP_SUPPORT_FIELD(bool, tun_eth_type, "Tunnel Ethernet Type")
 
 /* Indicates support for various fields. This defines how flows will be
  * serialised. */
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 2c8197fb7307..aa6b005fb9d0 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -8081,6 +8081,8 @@ xlate_wc_init(struct xlate_ctx *ctx)
 static void
 xlate_wc_finish(struct xlate_ctx *ctx)
 {
+    struct ofproto_dpif *ofproto = ctx->xbridge->ofproto;
+    struct dpif_backer *backer = ofproto->backer;
     int i;
 
     /* Clear the metadata and register wildcard masks, because we won't
@@ -8148,9 +8150,14 @@ xlate_wc_finish(struct xlate_ctx *ctx)
             ctx->wc->masks.vlans[i].tci = 0;
         }
     }
-    /* Clear tunnel wc bits if original packet is non-tunnel. */
+    /* Handle tunnel wildcarding and unwildcarding. */
     if (!flow_tnl_dst_is_set(&ctx->xin->upcall_flow->tunnel)) {
+        /* Clear tunnel wc bits if original packet is non-tunnel. */
         memset(&ctx->wc->masks.tunnel, 0, sizeof ctx->wc->masks.tunnel);
+    } else if (backer->rt_support.odp.tun_eth_type &&
+               ctx->xin->upcall_flow->tunnel.eth_type != 0) {
+        /* Unwildcard tunnel eth_type when supported and present. */
+        ctx->wc->masks.tunnel.eth_type = OVS_BE16_MAX;
     }
 }
 
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 4a200dd08828..f5323355a237 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -1659,6 +1659,75 @@ check_psample(struct dpif_backer *backer)
     return supported;
 }
 
+static bool
+check_tun_eth_type(struct dpif_backer *backer)
+{
+    struct flow flow;
+    struct odputil_keybuf keybuf;
+    struct ofpbuf key;
+    struct ofpbuf reply;
+    struct dpif_flow returned_flow;
+    uint64_t stub[DPIF_FLOW_BUFSIZE / 8];
+    bool enable = false;
+    ovs_be16 expected_eth_type = htons(ETH_TYPE_IP);
+    struct odp_flow_key_parms odp_parms = {
+        .flow = &flow,
+        .support = {
+            .tun_eth_type = true,
+        },
+    };
+
+    memset(&flow, 0, sizeof flow);
+    flow.tunnel.eth_type = expected_eth_type;
+    flow.tunnel.ip_dst = htonl(0x01020304);
+    flow.tunnel.ip_src = htonl(0x05060708);
+    flow.dl_type = htons(ETH_TYPE_IP);
+
+    ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
+    odp_flow_key_from_flow(&odp_parms, &key);
+
+    /* Try to install the flow */
+    int error = dpif_flow_put(backer->dpif,
+                              DPIF_FP_CREATE | DPIF_FP_PROBE,
+                              key.data, key.size, NULL, 0,
+                              NULL, 0, NULL, NON_PMD_CORE_ID, NULL);
+    if (error) {
+        goto out;
+    }
+
+    /* Read it back and verify the field is preserved */
+    ofpbuf_use_stack(&reply, &stub, sizeof stub);
+    error = dpif_flow_get(backer->dpif, key.data, key.size, NULL,
+                          NON_PMD_CORE_ID, &reply, &returned_flow);
+    if (error) {
+        goto cleanup;
+    }
+
+    /* Parse the returned flow and check if eth_type matches */
+    struct flow returned_flow_struct;
+    error = odp_flow_key_to_flow(returned_flow.key, returned_flow.key_len,
+                                  &returned_flow_struct, NULL);
+    if (!error && returned_flow_struct.tunnel.eth_type == expected_eth_type) {
+        enable = true;
+    }
+
+cleanup:
+    /* Clean up the test flow */
+    dpif_flow_del(backer->dpif, key.data, key.size, NULL,
+                  NON_PMD_CORE_ID, NULL);
+
+out:
+    if (enable) {
+        VLOG_INFO("%s: Datapath supports tun_eth_type",
+                  dpif_name(backer->dpif));
+    } else {
+        VLOG_INFO("%s: Datapath does not support tun_eth_type",
+                  dpif_name(backer->dpif));
+    }
+
+    return enable;
+}
+
 #define CHECK_FEATURE__(NAME, SUPPORT, FIELD, VALUE, ETHTYPE)               \
 static bool                                                                 \
 check_##NAME(struct dpif_backer *backer)                                    \
@@ -1759,6 +1828,7 @@ check_support(struct dpif_backer *backer)
     backer->rt_support.odp.ct_orig_tuple = check_ct_orig_tuple(backer);
     backer->rt_support.odp.ct_orig_tuple6 = check_ct_orig_tuple6(backer);
     backer->rt_support.odp.nd_ext = check_nd_extensions(backer);
+    backer->rt_support.odp.tun_eth_type = check_tun_eth_type(backer);
 }
 
 /* TC does not support offloading the explicit drop action. As such we need to
@@ -5924,6 +5994,7 @@ get_datapath_cap(const char *datapath_type, struct smap 
*cap)
     smap_add(cap, "ct_orig_tuple", s->odp.ct_orig_tuple ? "true" : "false");
     smap_add(cap, "ct_orig_tuple6", s->odp.ct_orig_tuple6 ? "true" : "false");
     smap_add(cap, "nd_ext", s->odp.nd_ext ? "true" : "false");
+    smap_add(cap, "tun_eth_type", s->odp.tun_eth_type ? "true" : "false");
 
     /* DPIF_SUPPORT_FIELDS */
     smap_add(cap, "masked_set_action",
diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
index f067a6c26c19..8c244c40df2b 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -381,6 +381,7 @@ tnl_wc_init(struct flow *flow, struct flow_wildcards *wc)
          * wildcarded, not to unwildcard them here. */
         wc->masks.tunnel.tp_src = 0;
         wc->masks.tunnel.tp_dst = 0;
+        wc->masks.tunnel.eth_type = 0;
 
         if (is_ip_any(flow)
             && IP_ECN_is_ce(flow->tunnel.ip_tos)) {
diff --git a/tests/nsh.at b/tests/nsh.at
index 022540dd68a4..d6ef0fdbb928 100644
--- a/tests/nsh.at
+++ b/tests/nsh.at
@@ -719,8 +719,8 @@ AT_CHECK([
     ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | 
sort
 ], [0], [flow-dump from the main thread:
 
recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no),
 packets:1, bytes:98, used:0.0s, 
actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3000,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(4789)
-recirc_id(0),tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(+df-csum+key)),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(np=1,spi=0x3000,si=255),
 packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x1)
-recirc_id(0x1),tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(+df-csum+key)),in_port(4789),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(frag=no),
 packets:1, bytes:84, used:0.0s, 
actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6
+recirc_id(0),tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,eth_type=0x800,flags(+df-csum+key)),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(np=1,spi=0x3000,si=255),
 packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x1)
+recirc_id(0x1),tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,eth_type=0x800,flags(+df-csum+key)),in_port(4789),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(frag=no),
 packets:1, bytes:84, used:0.0s, 
actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6
 ])
 
 AT_CHECK([
@@ -773,9 +773,9 @@ AT_CHECK([
     ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | 
sort
 ], [0], [flow-dump from the main thread:
 
recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20/255.255.255.248,frag=no),
 packets:1, bytes:98, used:0.0s, 
actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3020,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(4789)
-recirc_id(0),tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,flags(+df-csum+key)),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(spi=0x3020,si=255),
 packets:1, bytes:108, used:0.0s, 
actions:push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),set(nsh(spi=0x3020,si=254)),pop_eth,tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(src=30.0.0.2,dst=30.0.0.3)),tnl_pop(4789)
-recirc_id(0),tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(+df-csum+key)),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(np=1,spi=0x3020,si=254),
 packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x2)
-recirc_id(0x2),tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(+df-csum+key)),in_port(4789),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(frag=no),
 packets:1, bytes:84, used:0.0s, 
actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6
+recirc_id(0),tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,eth_type=0x800,flags(+df-csum+key)),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(spi=0x3020,si=255),
 packets:1, bytes:108, used:0.0s, 
actions:push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),set(nsh(spi=0x3020,si=254)),pop_eth,tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(src=30.0.0.2,dst=30.0.0.3)),tnl_pop(4789)
+recirc_id(0),tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,eth_type=0x800,flags(+df-csum+key)),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(np=1,spi=0x3020,si=254),
 packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x2)
+recirc_id(0x2),tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,eth_type=0x800,flags(+df-csum+key)),in_port(4789),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(frag=no),
 packets:1, bytes:84, used:0.0s, 
actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6
 ])
 
 AT_CHECK([
diff --git a/tests/packet-type-aware.at b/tests/packet-type-aware.at
index cebd8e6eeb46..134b94f7c2ac 100644
--- a/tests/packet-type-aware.at
+++ b/tests/packet-type-aware.at
@@ -324,7 +324,7 @@ AT_CHECK([
     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v 
ipv6 | sort
 ], [0], [flow-dump from the main thread:
 
recirc_id(0),in_port(n1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no),
 packets:1, bytes:98, used:0.0s, 
actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(gre_sys)
-recirc_id(0),tunnel(src=30.0.0.1,dst=30.0.0.3,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no),
 packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:03)),n3
+recirc_id(0),tunnel(src=30.0.0.1,dst=30.0.0.3,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no),
 packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:03)),n3
 ])
 
 # Clear up megaflow cache
@@ -342,7 +342,7 @@ AT_CHECK([
     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v 
ipv6 | sort
 ], [0], [flow-dump from the main thread:
 
recirc_id(0),in_port(n1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no),
 packets:1, bytes:98, used:0.0s, 
actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(gre_sys)
-recirc_id(0),tunnel(src=20.0.0.1,dst=20.0.0.2,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=46:1e:7d:1a:95:a1),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no),
 packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:02)),n2
+recirc_id(0),tunnel(src=20.0.0.1,dst=20.0.0.2,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=46:1e:7d:1a:95:a1),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no),
 packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:02)),n2
 ])
 
 # Clear up megaflow cache
@@ -360,7 +360,7 @@ AT_CHECK([
     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v 
ipv6 | sort
 ], [0], [flow-dump from the main thread:
 
recirc_id(0),in_port(n2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no),
 packets:1, bytes:98, used:0.0s, 
actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys)
-recirc_id(0),tunnel(src=10.0.0.2,dst=10.0.0.1,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=3a:6d:d2:09:9c:ab),eth_type(0x0800),ipv4(dst=192.168.10.10,frag=no),
 packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:01)),n1
+recirc_id(0),tunnel(src=10.0.0.2,dst=10.0.0.1,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=3a:6d:d2:09:9c:ab),eth_type(0x0800),ipv4(dst=192.168.10.10,frag=no),
 packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:01)),n1
 ])
 
 # Clear up megaflow cache
@@ -378,8 +378,8 @@ AT_CHECK([
     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v 
ipv6 | sort
 ], [0], [flow-dump from the main thread:
 
recirc_id(0),in_port(n2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no),
 packets:1, bytes:98, used:0.0s, 
actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys)
-recirc_id(0),tunnel(src=10.0.0.2,dst=10.0.0.1,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no),
 packets:1, bytes:98, used:0.0s, 
actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(gre_sys)
-recirc_id(0),tunnel(src=30.0.0.1,dst=30.0.0.3,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no),
 packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:03)),n3
+recirc_id(0),tunnel(src=10.0.0.2,dst=10.0.0.1,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no),
 packets:1, bytes:98, used:0.0s, 
actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(gre_sys)
+recirc_id(0),tunnel(src=30.0.0.1,dst=30.0.0.3,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no),
 packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:03)),n3
 ])
 
 # Clear up megaflow cache
@@ -397,8 +397,8 @@ AT_CHECK([
     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v 
ipv6 | sort
 ], [0], [flow-dump from the main thread:
 
recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no),
 packets:1, bytes:98, used:0.0s, 
actions:pop_eth,tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys)
-recirc_id(0),tunnel(src=10.0.0.2,dst=10.0.0.1,flags(+df-csum)),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,frag=no),
 packets:1, bytes:84, used:0.0s, 
actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:01),n1
-recirc_id(0),tunnel(src=20.0.0.3,dst=20.0.0.2,flags(+df-csum)),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no),
 packets:1, bytes:84, used:0.0s, 
actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys)
+recirc_id(0),tunnel(src=10.0.0.2,dst=10.0.0.1,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,frag=no),
 packets:1, bytes:84, used:0.0s, 
actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:01),n1
+recirc_id(0),tunnel(src=20.0.0.3,dst=20.0.0.2,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no),
 packets:1, bytes:84, used:0.0s, 
actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys)
 ])
 
 # Clear up megaflow cache
@@ -416,7 +416,7 @@ AT_CHECK([
     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v 
ipv6 | sort
 ], [0], [flow-dump from the main thread:
 
recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no),
 packets:1, bytes:98, used:0.0s, 
actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys)
-recirc_id(0),tunnel(src=20.0.0.3,dst=20.0.0.2,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=46:1e:7d:1a:95:a1),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no),
 packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:02)),n2
+recirc_id(0),tunnel(src=20.0.0.3,dst=20.0.0.2,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=46:1e:7d:1a:95:a1),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no),
 packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:02)),n2
 ])
 
 ### Check the received packets
@@ -502,7 +502,7 @@ AT_CHECK([
     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v 
ipv6 | sort
 ], [0], [flow-dump from the main thread:
 
recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no),
 packets:1, bytes:98, used:0.0s, 
actions:pop_eth,tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys)
-recirc_id(0),tunnel(src=20.0.0.3,dst=20.0.0.2,flags(+df-csum)),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no),
 packets:1, bytes:84, used:0.0s, actions:drop
+recirc_id(0),tunnel(src=20.0.0.3,dst=20.0.0.2,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no),
 packets:1, bytes:84, used:0.0s, actions:drop
 ])
 
 OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
@@ -1015,8 +1015,8 @@ AT_CHECK([
     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v 
ipv6 | sort
 ], [0], [flow-dump from the main thread:
 
recirc_id(0),in_port(p0),packet_type(ns=0,id=0),eth(src=aa:bb:cc:00:00:02,dst=aa:bb:cc:00:00:01),eth_type(0x0800),ipv4(dst=20.0.0.1,proto=47,frag=no),
 packets:3, bytes:378, used:0.0s, actions:tnl_pop(gre_sys)
-recirc_id(0),tunnel(src=20.0.0.2,dst=20.0.0.1,flags(+df-csum)),in_port(gre_sys),packet_type(ns=1,id=0x8847),eth_type(0x8847),mpls(label=999/0x0,tc=0/0,ttl=64/0x0,bos=1/1),
 packets:3, bytes:264, used:0.0s, 
actions:push_eth(src=00:00:00:00:00:00,dst=00:00:00:00:00:00),pop_mpls(eth_type=0x800),recirc(0x1)
-recirc_id(0x1),tunnel(src=20.0.0.2,dst=20.0.0.1,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=1,ttl=64,frag=no),
 packets:3, bytes:294, used:0.0s, actions:set(ipv4(ttl=63)),int-br
+recirc_id(0),tunnel(src=20.0.0.2,dst=20.0.0.1,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=1,id=0x8847),eth_type(0x8847),mpls(label=999/0x0,tc=0/0,ttl=64/0x0,bos=1/1),
 packets:3, bytes:264, used:0.0s, 
actions:push_eth(src=00:00:00:00:00:00,dst=00:00:00:00:00:00),pop_mpls(eth_type=0x800),recirc(0x1)
+recirc_id(0x1),tunnel(src=20.0.0.2,dst=20.0.0.1,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=1,ttl=64,frag=no),
 packets:3, bytes:294, used:0.0s, actions:set(ipv4(ttl=63)),int-br
 ])
 
 ovs-appctl time/warp 1000
diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at
index 39fbd2d35f55..08d31269f49a 100644
--- a/tests/tunnel-push-pop-ipv6.at
+++ b/tests/tunnel-push-pop-ipv6.at
@@ -571,7 +571,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
-recirc_id(0),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)),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,controller(reason=1,dont_send=0,continuation=0,recirc_id=3,rule_cookie=0,controller_id=0,max_len=65535))
+recirc_id(0),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}),eth_type=0x86dd,flags(-df-csum+key)),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,controller(reason=1,dont_send=0,continuation=0,recirc_id=3,rule_cookie=0,controller_id=0,max_len=65535))
 ])
 
 dnl Receive VXLAN with different MAC and verify that the neigh cache gets 
updated
diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
index 795817d62246..e370ed318fd3 100644
--- a/tests/tunnel-push-pop.at
+++ b/tests/tunnel-push-pop.at
@@ -684,7 +684,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)' | sed -e 
's/recirc_id=[[0-9]]*/recirc_id=<cleared>/g'], [0], [dnl
-recirc_id(0),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)),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,controller(reason=1,dont_send=0,continuation=0,recirc_id=<cleared>,rule_cookie=0,controller_id=0,max_len=65535))
+recirc_id(0),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}),eth_type=0x800,flags(+df-csum+key)),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,controller(reason=1,dont_send=0,continuation=0,recirc_id=<cleared>,rule_cookie=0,controller_id=0,max_len=65535))
 ])
 
 dnl Receive VXLAN with different MAC and verify that the neigh cache gets 
updated
diff --git a/tests/tunnel.at b/tests/tunnel.at
index e1a16138fa29..fc2ed9f5b9c9 100644
--- a/tests/tunnel.at
+++ b/tests/tunnel.at
@@ -1354,3 +1354,47 @@ AT_CHECK_UNQUOTED([tail -1 stdout], [0],
 
 OVS_VSWITCHD_STOP
 AT_CLEANUP
+
+AT_SETUP([tunnel - decap and re-encap with outer IP version conversion])
+OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy 
ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00])
+AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], 
[0])
+AT_CHECK([ovs-vsctl add-port int-br t1 -- set Interface t1 type=vxlan \
+                       options:remote_ip=1.1.1.1 options:key=122 \
+                    -- add-port int-br t2 -- set Interface t2 type=geneve \
+                       options:remote_ip=2001:cafe::1 options:key=123 \
+                       ], [0])
+
+dnl Setup dummy interface IP addresses.
+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.1.2/24], [0], [OK
+])
+AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0 2001:cafe::2/24], [0], [OK
+])
+dnl Checking that a local routes for added IPs were successfully installed.
+AT_CHECK([ovs-appctl ovs/route/show | grep Cached | sort], [0], [dnl
+Cached: 1.1.1.0/24 dev br0 SRC 1.1.1.2 local
+Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::2 local
+])
+
+AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+AT_CHECK([ovs-appctl revalidator/wait])
+
+dnl Add entries
+AT_CHECK([ovs-appctl tnl/neigh/set br0 1.1.1.1 aa:bb:cc:00:00:01], [0], [OK
+])
+AT_CHECK([ovs-appctl tnl/neigh/set br0 2001:cafe::1 aa:bb:cc:00:00:01], [0], 
[OK
+])
+
+AT_CHECK([ovs-ofctl add-flow int-br 
'in_port=t1,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_id=0x7a,actions=set_field:2001:cafe::2->tun_ipv6_src,set_field:2001:cafe::1->tun_ipv6_dst,set_field:0x7b->tun_id,set_field:0.0.0.0->tun_src,set_field:0.0.0.0->tun_dst,t2'])
+AT_CHECK([ovs-ofctl add-flow int-br 
'in_port=t2,tun_ipv6_src=2001:cafe::1,tun_ipv6_dst=2001:cafe::2,tun_id=0x7b,actions=set_field:1.1.1.2->tun_src,set_field:1.1.1.1->tun_dst,set_field:0x7a->tun_id,t1'])
+
+AT_CHECK([ovs-appctl netdev-dummy/receive p0 
'aa55aa550000001b213cab6408004500004e000140004011369a010101010101010212b512b5003a05e30800000000007a00fe71d883724fbeb6f4e1494a08004500001c000140004001fedd1e0000011e0000020000ffff00000000'])
+
+AT_CHECK([ovs-appctl netdev-dummy/receive p0 
'aa55aa550000001b213cab6486dd60000000003a11402001cafe0000000000000000000000012001cafe00000000000000000000000217c117c1003acb740000655800007b00fe71d883724fbeb6f4e1494a08004500001c000140004001fedd1e0000011e0000020000ffff00000000'])
+
+AT_CHECK([ovs-appctl dpctl/dump-flows | strip_ufid | strip_used | strip_stats 
| grep tunnel | sort], [0],
+  
[recirc_id(0),tunnel(tun_id=0x7a,src=1.1.1.1,dst=1.1.1.2,eth_type=0x800,flags(+df+csum+key)),in_port(4789),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no),
 packets:0, bytes:0, used:never, 
actions:tnl_push(tnl_port(6081),header(size=70,type=5,eth(dst=00:1b:21:3c:ab:64,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::2,dst=2001:cafe::1,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x7b)),out_port(100)),1
+recirc_id(0),tunnel(tun_id=0x7b,ipv6_src=2001:cafe::1,ipv6_dst=2001:cafe::2,geneve(),eth_type=0x86dd,flags(-df+csum+key)),in_port(6081),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no),
 packets:0, bytes:0, used:never, 
actions:tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=00:1b:21:3c:ab:64,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.1.2,dst=1.1.1.1,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7a)),out_port(100)),1
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
-- 
2.47.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to