diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c
index c7a29934537e..658c871015f9 100644
--- a/lib/netdev-native-tnl.c
+++ b/lib/netdev-native-tnl.c
@@ -463,10 +463,12 @@ netdev_gre_build_header(const struct netdev *netdev,
 
     greh = netdev_tnl_ip_build_header(data, params, IPPROTO_GRE);
 
-    if (tnl_cfg->is_layer3) {
-        greh->protocol = params->flow->dl_type;
-    } else {
+    if (params->flow->packet_type == htonl(PT_ETH)) {
         greh->protocol = htons(ETH_TYPE_TEB);
+    } else if (pt_ns(params->flow->packet_type) == OFPHTN_ETHERTYPE) {
+        greh->protocol = pt_ns_type_be(params->flow->packet_type);
+    } else {
+        return 1;
     }
     greh->flags = 0;
 
@@ -575,8 +577,10 @@ netdev_vxlan_build_header(const struct netdev *netdev,
         put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS | VXLAN_HF_GPE));
         put_16aligned_be32(&vxh->vx_vni,
                            htonl(ntohll(params->flow->tunnel.tun_id) << 8));
-        if (tnl_cfg->is_layer3) {
-            switch (ntohs(params->flow->dl_type)) {
+        if (params->flow->packet_type == htonl(PT_ETH)) {
+            vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET;
+        } else if (pt_ns(params->flow->packet_type) == OFPHTN_ETHERTYPE){
+            switch (pt_ns_type(params->flow->packet_type)) {
             case ETH_TYPE_IP:
                 vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_IPV4;
                 break;
@@ -586,9 +590,13 @@ netdev_vxlan_build_header(const struct netdev *netdev,
             case ETH_TYPE_TEB:
                 vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET;
                 break;
+            default:
+                /* Drop packet. */
+                return 1;
+                break;
             }
         } else {
-            vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET;
+            return 1;
         }
     } else {
         put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index d18d58c87c20..623b7a0ee6c5 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -6154,7 +6154,7 @@ xlate_wc_init(struct xlate_ctx *ctx)
         netflow_mask_wc(&ctx->xin->flow, ctx->wc);
     }
 
-    tnl_wc_init(&ctx->xin->flow, ctx->wc);
+    tnl_wc_init(&ctx->xin->flow, ctx->wc, ctx->xbridge->packet_type_aware);
 }
 
 static void
diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
index e27a9fb75d08..caf01be5f14b 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -361,7 +361,8 @@ tnl_process_ecn(struct flow *flow)
 }
 
 void
-tnl_wc_init(struct flow *flow, struct flow_wildcards *wc)
+tnl_wc_init(struct flow *flow, struct flow_wildcards *wc,
+            bool packet_type_aware)
 {
     if (tnl_port_should_receive(flow)) {
         wc->masks.tunnel.tun_id = OVS_BE64_MAX;
@@ -386,8 +387,10 @@ 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;
+        if (!packet_type_aware) {
+            /* Match on packet_type for tunneled packets.*/
+            wc->masks.packet_type = OVS_BE32_MAX;
+        }
     }
 }
 
@@ -566,8 +569,21 @@ tnl_find(const struct flow *flow) OVS_REQ_RDLOCK(rwlock)
                     match.in_key_flow = in_key_flow;
                     match.ip_dst_flow = ip_dst_flow;
                     match.ip_src_flow = ip_src == IP_SRC_FLOW;
-                    match.is_layer3 = flow->packet_type != htonl(PT_ETH);
 
+                    /* If it's about a Non-ethernet packet then we look for a
+                     * layer3 tunnel port first, as it would be attached to a
+                     * non-PTAP bridge. Then for a versatile tunnel port as it
+                     * would be attached to a PTAP bridge. */
+                    if (pt_ns(flow->packet_type) == OFPHTN_ETHERTYPE) {
+                        /* Try to find a layer3 port first. */
+                        match.is_layer3 = true;
+                        tnl_port = tnl_find_exact(&match, map);
+                        if (tnl_port) {
+                            return tnl_port;
+                        }
+                    }
+                    /* Check for a non-layer3 or versatile tunnel port. */
+                    match.is_layer3 = false;
                     tnl_port = tnl_find_exact(&match, map);
                     if (tnl_port) {
                         return tnl_port;
diff --git a/ofproto/tunnel.h b/ofproto/tunnel.h
index b0ec67c2bd74..dc004cc18b66 100644
--- a/ofproto/tunnel.h
+++ b/ofproto/tunnel.h
@@ -39,7 +39,7 @@ int tnl_port_add(const struct ofport_dpif *, const struct netdev *,
 void tnl_port_del(const struct ofport_dpif *);
 
 const struct ofport_dpif *tnl_port_receive(const struct flow *);
-void tnl_wc_init(struct flow *, struct flow_wildcards *);
+void tnl_wc_init(struct flow *, struct flow_wildcards *, bool);
 bool tnl_process_ecn(struct flow *);
 odp_port_t tnl_port_send(const struct ofport_dpif *, struct flow *,
                          struct flow_wildcards *wc);
