diff --git a/tests/automake.mk b/tests/automake.mk
index c6bd120..08d5a2d 100644
--- a/tests/automake.mk
+++ b/tests/automake.mk
@@ -95,7 +95,8 @@ TESTSUITE_AT = \
 	tests/ovn-sbctl.at \
 	tests/ovn-controller.at \
 	tests/ovn-controller-vtep.at \
-	tests/mcast-snooping.at
+	tests/mcast-snooping.at \
+	tests/packet-type-aware.at
 
 SYSTEM_KMOD_TESTSUITE_AT = \
 	tests/system-common-macros.at \
@@ -105,7 +106,8 @@ SYSTEM_KMOD_TESTSUITE_AT = \
 SYSTEM_USERSPACE_TESTSUITE_AT = \
 	tests/system-userspace-testsuite.at \
 	tests/system-ovn.at \
-	tests/system-userspace-macros.at
+	tests/system-userspace-macros.at \
+	tests/system-userspace-packet-type-aware.at
 
 SYSTEM_TESTSUITE_AT = \
 	tests/system-common-macros.at \
diff --git a/tests/packet-type-aware.at b/tests/packet-type-aware.at
new file mode 100644
index 0000000..976b0fd
--- /dev/null
+++ b/tests/packet-type-aware.at
@@ -0,0 +1,540 @@
+AT_BANNER([packet-type-aware pipeline])
+
+AT_SETUP([ptap - create packet-type-aware bridge])
+
+OVS_VSWITCHD_START([])
+
+AT_CHECK([
+    ovs-vsctl set bridge br0 \
+    datapath_type=dummy \
+    other-config:packet-type-aware=true
+], [0])
+
+AT_CHECK([ovs-vsctl list bridge br0 | grep other_config], [0], [dnl
+other_config        : {datapath-id="fedcba9876543210", hwaddr="aa:55:aa:55:00:00", packet-type-aware="true"}
+])
+
+AT_CHECK([ovs-ofctl -Oopenflow13 dump-table-features br0 | grep packet_type], [0], [dnl
+      packet_type: exact match or wildcard
+])
+AT_CHECK([ovs-ofctl -Oopenflow14 dump-table-features br0 | grep packet_type], [0], [dnl
+      packet_type: exact match or wildcard
+])
+AT_CHECK([ovs-ofctl -Oopenflow15 dump-table-features br0 | grep packet_type], [0], [dnl
+      packet_type: exact match or wildcard
+])
+
+AT_CHECK([
+    ovs-vsctl set bridge br0 other-config:packet-type-aware=false
+], [0])
+
+AT_CHECK([ovs-vsctl list bridge br0 | grep other_config], [0], [dnl
+other_config        : {datapath-id="fedcba9876543210", hwaddr="aa:55:aa:55:00:00", packet-type-aware="false"}
+])
+
+AT_CHECK([ovs-ofctl -Oopenflow13 dump-table-features br0 | grep packet_type], [1])
+AT_CHECK([ovs-ofctl -Oopenflow14 dump-table-features br0 | grep packet_type], [1])
+AT_CHECK([ovs-ofctl -Oopenflow15 dump-table-features br0 | grep packet_type], [1])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+
+AT_SETUP([ptap - legal flow entries in ptap bridge])
+
+OVS_VSWITCHD_START([])
+
+AT_CHECK([
+    ovs-vsctl set bridge br0 \
+    datapath_type=dummy \
+    protocols=OpenFlow10,OpenFlow13,OpenFlow14,OpenFlow15 \
+    other-config:packet-type-aware=true
+], [0])
+
+AT_CHECK([
+    ovs-ofctl del-flows br0
+    ovs-ofctl -Oopenflow13 add-flow br0 priority=1,dl_src=11:22:33:44:55:66,eth_type=0x1234,actions=drop
+    ovs-ofctl -Oopenflow14 add-flow br0 priority=1,ip,nw_dst=10.11.12.13,actions=drop
+    ovs-ofctl -Oopenflow15 add-flow br0 priority=1,ipv6,nw_proto=6,actions=drop
+    ovs-ofctl -Oopenflow14 add-flow br0 priority=2,packet_type=\(0,0x0\),dl_src=11:22:33:44:55:66,dl_type=0x4567,actions=drop
+    ovs-ofctl -Oopenflow15 add-flow br0 priority=2,packet_type=\(0,0x0\),arp,arp_tpa=10.11.12.13,actions=drop
+    ovs-ofctl -Oopenflow15 add-flow br0 priority=3,packet_type=\(1,0x806\),arp_tpa=10.11.12.13,actions=drop
+    ovs-ofctl -Oopenflow13 add-flow br0 priority=3,packet_type=\(1,0x800\),nw_dst=10.11.12.13,actions=drop
+    ovs-ofctl -Oopenflow14 add-flow br0 priority=3,packet_type=\(1,0x86dd\),ipv6_dst=1234:5678::/32,actions=drop
+], [0])
+
+AT_CHECK([ovs-ofctl -Oopenflow15 dump-flows br0 | ofctl_strip | sort | grep actions], [0], [dnl
+ priority=1,packet_type=(0,0x0),dl_src=11:22:33:44:55:66,dl_type=0x1234 actions=drop
+ priority=1,packet_type=(0,0x0),ip,nw_dst=10.11.12.13 actions=drop
+ priority=1,packet_type=(0,0x0),tcp6 actions=drop
+ priority=2,packet_type=(0,0x0),arp,arp_tpa=10.11.12.13 actions=drop
+ priority=2,packet_type=(0,0x0),dl_src=11:22:33:44:55:66,dl_type=0x4567 actions=drop
+ priority=3,packet_type=(1,0x800),nw_dst=10.11.12.13 actions=drop
+ priority=3,packet_type=(1,0x806),arp_tpa=10.11.12.13 actions=drop
+ priority=3,packet_type=(1,0x86dd),ipv6_dst=1234:5678::/32 actions=drop
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+
+AT_SETUP([ptap - triangle bridge setup with L2 and L3 GRE tunnels])
+
+AT_SKIP_IF([test x"$USER" != xroot])
+
+########################
+# GRE tunneling test setup for PTAP bridge
+#
+#     192.168.10.10           192.168.10.20             192.168.10.30
+#          n1                       n2                        n3
+#          |                        |                         |
+#   +------o------+          +------o------+           +------o------+
+#   |    br-in1   |          |    br-in2   |           |    br-in3   |
+#   |             |          |   (PTAP)    |           |             |
+#   +------o------+          +------o------+           +------o------+
+#         gre                      gre                       gre
+#   10.0.0.1                (10.0.0.2)                (10.0.0.3)
+#  (20.0.0.1)                20.0.0.2                 (20.0.0.3)
+#  (30.0.0.1) LOCAL         (30.0.0.2) LOCAL           30.0.0.3  LOCAL
+#   +-----------o-+          +-----------o-+           +-----------o-+
+#   |    br-p1    |          |    br-p2    |           |    br-p3    |
+#   +------o------+          +------o------+           +------o------+
+#     p1-0 |                        | p2-0                    | p3-0
+#     p0-1 |                        | p0-2                    | p0-3
+#       +--o------------------------o-------------------------o--+
+#       |                          br0                           |
+#       +--------------------------------------------------------+
+#"
+#   GRE tunnel ports:
+#      No     Bridge      Name        Type        Remote bridge & ports
+#     -----------------------------------------------------------------------
+#      1020   br-in1      gre-12      l2          br-in2 2010 (versatile)
+#      1021   br-in1      gre-12_l3   l3                same
+#      1030   br-in1      gre-13      l2          br-in3 3010 (l2)
+#      2010   br-in2      gre-21      versatile   br-in1 1020 (l2), 1021 (l3)
+#      2030   br-in2      gre-13      versatile   br-in3 3020 (l2), 3021 (l3)
+#      3010   br-in1      gre-31      l2          br-in1 1030 (l2)
+#      3020   br-in1      gre-32      l2          br-in2 2010 (versatile)
+#      3021   br-in1      gre-32_l3   l3                same
+
+
+OVS_VSWITCHD_START([])
+
+HWADDR_BRP1=aa:55:00:00:00:01
+HWADDR_BRP2=aa:55:00:00:00:02
+HWADDR_BRP3=aa:55:00:00:00:03
+
+dnl Create veth ports to connect br0 with br-p1, br-p2 and br-p3
+AT_CHECK([ip link add p1-0 type veth peer name p0-1])
+AT_CHECK([ip link set p1-0 up])
+AT_CHECK([ip link set p0-1 up])
+AT_CHECK([ip link set dev p1-0 mtu 3300])
+AT_CHECK([ip link set dev p0-1 mtu 3300])
+on_exit 'ip link del p0-1'
+
+AT_CHECK([ip link add p2-0 type veth peer name p0-2])
+AT_CHECK([ip link set p2-0 up])
+AT_CHECK([ip link set p0-2 up])
+AT_CHECK([ip link set dev p2-0 mtu 3300])
+AT_CHECK([ip link set dev p0-2 mtu 3300])
+on_exit 'ip link del p0-2'
+
+AT_CHECK([ip link add p3-0 type veth peer name p0-3])
+AT_CHECK([ip link set p3-0 up])
+AT_CHECK([ip link set p0-3 up])
+AT_CHECK([ip link set dev p3-0 mtu 3300])
+AT_CHECK([ip link set dev p0-3 mtu 3300])
+on_exit 'ip link del p0-3'
+
+# Setup bridge infrastructure
+AT_CHECK([
+    ovs-vsctl add-br br-in1 -- \
+        set bridge br-in1 datapath_type=dummy fail-mode=standalone
+    ovs-vsctl add-br br-in2 -- \
+        set bridge br-in2 datapath_type=dummy fail-mode=standalone other-config:packet-type-aware=true
+    ovs-vsctl add-br br-in3 -- \
+        set bridge br-in3 datapath_type=dummy fail-mode=standalone
+    ovs-vsctl add-br br-p1 -- \
+        set bridge br-p1 datapath_type=dummy fail-mode=standalone other-config:hwaddr=$HWADDR_BRP1
+    ovs-vsctl add-br br-p2 -- \
+        set bridge br-p2 datapath_type=dummy fail-mode=standalone other-config:hwaddr=$HWADDR_BRP2
+    ovs-vsctl add-br br-p3 -- \
+        set bridge br-p3 datapath_type=dummy fail-mode=standalone other-config:hwaddr=$HWADDR_BRP3
+
+    ovs-vsctl add-port br-p1 p1-0 -- set interface p1-0 ofport_request=2
+    ovs-vsctl add-port br-p2 p2-0 -- set interface p2-0 ofport_request=2
+    ovs-vsctl add-port br-p3 p3-0 -- set interface p3-0 ofport_request=2
+    ovs-vsctl add-port br0 p0-1 -- set interface p0-1 ofport_request=10
+    ovs-vsctl add-port br0 p0-2 -- set interface p0-2 ofport_request=20
+    ovs-vsctl add-port br0 p0-3 -- set interface p0-3 ofport_request=30
+
+    # Populate the MAC table of br0
+    ovs-ofctl del-flows br0
+    ovs-ofctl add-flow br0 dl_dst=$HWADDR_BRP1,actions=10
+    ovs-ofctl add-flow br0 dl_dst=$HWADDR_BRP2,actions=20
+    ovs-ofctl add-flow br0 dl_dst=$HWADDR_BRP3,actions=30
+
+    ovs-ofctl del-flows br-in1
+    ovs-ofctl del-flows br-in2
+    ovs-ofctl del-flows br-in3
+    ovs-ofctl del-flows br-p1
+    ovs-ofctl del-flows br-p2
+    ovs-ofctl del-flows br-p3
+], [0])
+
+# Get the MAC addresses of the tunnel end-point ports
+#HWADDR_BRP1=$(ovs-ofctl show br-p1 | grep LOCAL | sed 's/.*addr://')
+#HWADDR_BRP2=$(ovs-ofctl show br-p2 | grep LOCAL | sed 's/.*addr://')
+#HWADDR_BRP3=$(ovs-ofctl show br-p3 | grep LOCAL | sed 's/.*addr://')
+
+### Setup GRE tunnels
+AT_CHECK([
+    ovs-vsctl add-port br-in1 gre12 -- \
+        set interface gre12 type=gre options:remote_ip=10.0.0.2 ofport_request=1020
+    ovs-vsctl add-port br-in1 gre12_l3 -- \
+        set interface gre12_l3 type=gre options:remote_ip=10.0.0.2 ofport_request=1021 options:layer3=true
+    ovs-vsctl add-port br-in1 gre13 -- \
+        set interface gre13 type=gre options:remote_ip=10.0.0.3 ofport_request=1030
+
+    ovs-vsctl add-port br-in2 gre21 -- \
+        set interface gre21 type=gre options:remote_ip=20.0.0.1 ofport_request=2010
+    ovs-vsctl add-port br-in2 gre23 -- \
+        set interface gre23 type=gre options:remote_ip=20.0.0.3 ofport_request=2030
+
+    ovs-vsctl add-port br-in3 gre31 -- \
+        set interface gre31 type=gre options:remote_ip=30.0.0.1 ofport_request=3010
+    ovs-vsctl add-port br-in3 gre32 -- \
+        set interface gre32 type=gre options:remote_ip=30.0.0.2 ofport_request=3020
+    ovs-vsctl add-port br-in3 gre32_l3 -- \
+        set interface gre32_l3 type=gre options:remote_ip=30.0.0.2 ofport_request=3021 options:layer3=true
+
+    ovs-appctl netdev-dummy/ip4addr br-p1 10.0.0.1/24
+    ovs-appctl ovs/route/add 10.0.0.0/24 br-p1
+    ovs-appctl tnl/arp/set br-p1 10.0.0.1 $HWADDR_BRP1
+    ovs-appctl tnl/arp/set br-p1 10.0.0.2 $HWADDR_BRP2
+    ovs-appctl tnl/arp/set br-p1 10.0.0.3 $HWADDR_BRP3
+
+    ovs-appctl netdev-dummy/ip4addr br-p2 20.0.0.2/24
+    ovs-appctl ovs/route/add 20.0.0.0/24 br-p2
+    ovs-appctl tnl/arp/set br-p2 20.0.0.1 $HWADDR_BRP1
+    ovs-appctl tnl/arp/set br-p2 20.0.0.2 $HWADDR_BRP2
+    ovs-appctl tnl/arp/set br-p2 20.0.0.3 $HWADDR_BRP3
+
+    ovs-appctl netdev-dummy/ip4addr br-p3 30.0.0.3/24
+    ovs-appctl ovs/route/add 30.0.0.0/24 br-p3
+    ovs-appctl tnl/arp/set br-p3 30.0.0.1 $HWADDR_BRP1
+    ovs-appctl tnl/arp/set br-p3 30.0.0.2 $HWADDR_BRP2
+    ovs-appctl tnl/arp/set br-p3 30.0.0.3 $HWADDR_BRP3
+], [0], [stdout])
+
+AT_CHECK([
+    ovs-appctl ovs/route/show | grep User:
+], [0], [dnl
+User: 10.0.0.0/24 dev br-p1 SRC 10.0.0.1
+User: 20.0.0.0/24 dev br-p2 SRC 20.0.0.2
+User: 30.0.0.0/24 dev br-p3 SRC 30.0.0.3
+])
+
+AT_CHECK([
+    ovs-appctl tnl/neigh/show | grep br-p | sort
+], [0], [stdout])
+
+### Flows in br-p<x>to twist TEP IP addresses in tunnel IP headers
+AT_CHECK([
+    ovs-ofctl add-flow br-p1 in_port:LOCAL,actions=2
+    ovs-ofctl add-flow br-p1 in_port:2,ip,nw_dst:20.0.0.1,actions=mod_nw_dst:10.0.0.1,mod_nw_src:10.0.0.2,LOCAL
+    ovs-ofctl add-flow br-p1 in_port:2,ip,nw_dst:30.0.0.1,actions=mod_nw_dst:10.0.0.1,mod_nw_src:10.0.0.3,LOCAL
+
+    ovs-ofctl add-flow br-p2 in_port:LOCAL,actions=2
+    ovs-ofctl add-flow br-p2 in_port:2,ip,nw_dst:10.0.0.2,actions=mod_nw_dst:20.0.0.2,mod_nw_src:20.0.0.1,LOCAL
+    ovs-ofctl add-flow br-p2 in_port:2,ip,nw_dst:30.0.0.2,actions=mod_nw_dst:20.0.0.2,mod_nw_src:20.0.0.3,LOCAL
+
+    ovs-ofctl add-flow br-p3 in_port:LOCAL,actions=2
+    ovs-ofctl add-flow br-p3 in_port:2,ip,nw_dst:10.0.0.3,actions=mod_nw_dst:30.0.0.3,mod_nw_src:30.0.0.1,LOCAL
+    ovs-ofctl add-flow br-p3 in_port:2,ip,nw_dst:20.0.0.3,actions=mod_nw_dst:30.0.0.3,mod_nw_src:30.0.0.2,LOCAL
+], [0])
+
+AT_CHECK([
+    ovs-ofctl dump-flows br-p1 | ofctl_strip | sort | grep actions
+    ovs-ofctl dump-flows br-p2 | ofctl_strip | sort | grep actions
+    ovs-ofctl dump-flows br-p3 | ofctl_strip | sort | grep actions
+], [0], [dnl
+ in_port=LOCAL actions=output:2
+ ip,in_port=2,nw_dst=20.0.0.1 actions=mod_nw_dst:10.0.0.1,mod_nw_src:10.0.0.2,LOCAL
+ ip,in_port=2,nw_dst=30.0.0.1 actions=mod_nw_dst:10.0.0.1,mod_nw_src:10.0.0.3,LOCAL
+ in_port=LOCAL actions=output:2
+ ip,in_port=2,nw_dst=10.0.0.2 actions=mod_nw_dst:20.0.0.2,mod_nw_src:20.0.0.1,LOCAL
+ ip,in_port=2,nw_dst=30.0.0.2 actions=mod_nw_dst:20.0.0.2,mod_nw_src:20.0.0.3,LOCAL
+ in_port=LOCAL actions=output:2
+ ip,in_port=2,nw_dst=10.0.0.3 actions=mod_nw_dst:30.0.0.3,mod_nw_src:30.0.0.1,LOCAL
+ ip,in_port=2,nw_dst=20.0.0.3 actions=mod_nw_dst:30.0.0.3,mod_nw_src:30.0.0.2,LOCAL
+])
+
+### Setup test ports for traffic injection
+N1_IP=192.168.10.10
+N2_IP=192.168.10.20
+N3_IP=192.168.10.30
+N1_MAC=aa:55:aa:55:00:01
+N2_MAC=aa:55:aa:55:00:02
+N3_MAC=aa:55:aa:55:00:03
+N1_OFPORT=10
+N2_OFPORT=20
+N3_OFPORT=30
+
+AT_CHECK([
+    ovs-vsctl add-port br-in1 n1 -- \
+        set interface n1 type=dummy ofport_request=$N1_OFPORT options:tx_pcap=n1.pcap
+    ovs-vsctl add-port br-in2 n2 -- \
+        set interface n2 type=dummy ofport_request=$N2_OFPORT options:tx_pcap=n2.pcap
+    ovs-vsctl add-port br-in3 n3 -- \
+        set interface n3 type=dummy ofport_request=$N3_OFPORT options:tx_pcap=n3.pcap
+], [0])
+
+#N1_DPPORT=$(ovs-appctl dpif/show | grep "n1 10" | sed 's|.*/\([[0-9]]*\):.*|\1|')
+#N2_DPPORT=$(ovs-appctl dpif/show | grep "n2 20" | sed 's|.*/\([[0-9]]*\):.*|\1|')
+#N3_DPPORT=$(ovs-appctl dpif/show | grep "n3 30" | sed 's|.*/\([[0-9]]*\):.*|\1|')
+
+### Verify datapath configuration
+AT_CHECK([
+    ovs-appctl dpif/show | grep -v hit | sed 's/\t/    /g'
+], [0], [dnl
+    br-in1:
+        br-in1 65534/101: (dummy-internal)
+        gre12 1020/10: (gre: remote_ip=10.0.0.2)
+        gre12_l3 1021/10: (gre: layer3=true, remote_ip=10.0.0.2)
+        gre13 1030/10: (gre: remote_ip=10.0.0.3)
+        n1 10/11: (dummy)
+    br-in2:
+        br-in2 65534/102: (dummy-internal)
+        gre21 2010/10: (gre: remote_ip=20.0.0.1)
+        gre23 2030/10: (gre: remote_ip=20.0.0.3)
+        n2 20/12: (dummy)
+    br-in3:
+        br-in3 65534/103: (dummy-internal)
+        gre31 3010/10: (gre: remote_ip=30.0.0.1)
+        gre32 3020/10: (gre: remote_ip=30.0.0.2)
+        gre32_l3 3021/10: (gre: layer3=true, remote_ip=30.0.0.2)
+        n3 30/13: (dummy)
+    br-p1:
+        br-p1 65534/1: (dummy-internal)
+        p1-0 2/4: (system)
+    br-p2:
+        br-p2 65534/2: (dummy-internal)
+        p2-0 2/5: (system)
+    br-p3:
+        br-p3 65534/3: (dummy-internal)
+        p3-0 2/6: (system)
+    br0:
+        br0 65534/100: (dummy-internal)
+        p0-1 10/7: (system)
+        p0-2 20/8: (system)
+        p0-3 30/9: (system)
+])
+
+### Test L3 forwarding flows
+AT_CHECK([
+    ovs-ofctl add-flow br-in1 ip,nw_dst=$N1_IP,actions=mod_dl_dst:$N1_MAC,$N1_OFPORT # Local route to N1
+    ovs-ofctl add-flow br-in1 ip,nw_dst=$N2_IP,actions=1020 # Route to N2 via the L2 tunnel to br-in2
+    ovs-ofctl add-flow br-in1 ip,nw_dst=$N3_IP,actions=1030 # Route to N3 direct through L2 tunnel
+
+    ovs-ofctl add-flow br-in2 ip,nw_dst=$N2_IP,actions=mod_dl_dst:$N2_MAC,$N2_OFPORT # Local route to N2 for ethernet packets
+    ovs-ofctl add-flow br-in2 ip,nw_dst=$N1_IP,actions=2010 # Route to N1 for ethernet packet
+    ovs-ofctl add-flow br-in2 packet_type=\(1,0x800\),nw_dst=$N1_IP,actions=2010 # Route to N1 for IP packets
+    ovs-ofctl add-flow br-in2 ip,nw_dst=$N3_IP,actions=2010 # Indirect route to N3 via br-in1 for ethernet packet
+    ovs-ofctl add-flow br-in2 packet_type=\(1,0x800\),nw_dst=$N3_IP,actions=2030 # Direct route to N3 for IP packets
+
+    ovs-ofctl add-flow br-in3 ip,nw_dst=$N3_IP,actions=mod_dl_dst:$N3_MAC,$N3_OFPORT # Local route to N1
+    ovs-ofctl add-flow br-in3 ip,nw_dst=$N2_IP,actions=3020 # Route to N2 via the L2 tunnel
+    ovs-ofctl add-flow br-in3 ip,nw_dst=$N1_IP,actions=3021 # Route to N1 via br-in2 through L3 tunnel
+], [0])
+
+AT_CHECK([
+    ovs-ofctl dump-flows br-in1 | ofctl_strip | sort | grep actions
+], [0], [dnl
+ ip,nw_dst=192.168.10.10 actions=mod_dl_dst:aa:55:aa:55:00:01,output:10
+ ip,nw_dst=192.168.10.20 actions=output:1020
+ ip,nw_dst=192.168.10.30 actions=output:1030
+])
+
+AT_CHECK([
+    ovs-ofctl dump-flows br-in2 | ofctl_strip | sort | grep actions
+], [0], [dnl
+ packet_type=(0,0x0),ip,nw_dst=192.168.10.10 actions=output:2010
+ packet_type=(0,0x0),ip,nw_dst=192.168.10.20 actions=mod_dl_dst:aa:55:aa:55:00:02,output:20
+ packet_type=(0,0x0),ip,nw_dst=192.168.10.30 actions=output:2010
+ packet_type=(1,0x800),nw_dst=192.168.10.10 actions=output:2010
+ packet_type=(1,0x800),nw_dst=192.168.10.30 actions=output:2030
+])
+
+AT_CHECK([
+    ovs-ofctl dump-flows br-in3 | ofctl_strip | sort | grep actions
+], [0], [dnl
+ ip,nw_dst=192.168.10.10 actions=output:3021
+ ip,nw_dst=192.168.10.20 actions=output:3020
+ ip,nw_dst=192.168.10.30 actions=mod_dl_dst:aa:55:aa:55:00:03,output:30
+])
+
+### Inject ICMP Echo request test packets
+
+# N1 to N3, via the L2 GRE tunnel between br-in1 and br-in3
+AT_CHECK([
+    ovs-appctl netdev-dummy/receive n1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+    ovs-appctl netdev-dummy/receive n1 1e2ce92a669e3a6dd2099cab0800450000548a83400040011aadc0a80a0ac0a80a1e0800b7170a4d0002fd509a5800000000de1c020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+], [0], [ignore])
+
+ovs-appctl time/warp 1000
+
+AT_CHECK([
+    ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+], [0], [flow-dump from non-dpdk interfaces:
+recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:136, used:0.0s, actions:4
+recirc_id(0),in_port(11),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(10),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(1))
+recirc_id(0),in_port(6),eth(dst=aa:55:00:00:00:03),eth_type(0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,frag=no), packets:1, bytes:136, used:0.0s, actions:set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(10)
+recirc_id(0),in_port(7),eth(dst=aa:55:00:00:00:03),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:136, used:0.0s, actions:9
+tunnel(src=30.0.0.1,dst=30.0.0.3,flags(-df-csum)),recirc_id(0),in_port(10),packet_type(ns=0,id=0x0),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)),13
+])
+
+# Clear up megaflow cache
+ovs-appctl time/warp 11000
+
+# N1 to N2 via the L2 GRE tunnel between br-in1 and br-in2
+AT_CHECK([
+    ovs-appctl netdev-dummy/receive n1 461e7d1a95a13a6dd2099cab080045000054500b40004001552fc0a80a0ac0a80a140800531f09a90001e9509a580000000055ba030000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+    ovs-appctl netdev-dummy/receive n1 461e7d1a95a13a6dd2099cab08004500005450934000400154a7c0a80a0ac0a80a140800f41d09a90002ea509a5800000000b3ba030000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+], [0], [ignore])
+
+ovs-appctl time/warp 1000
+
+AT_CHECK([
+    ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+], [0], [flow-dump from non-dpdk interfaces:
+recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:136, used:0.0s, actions:4
+recirc_id(0),in_port(11),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(10),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(1))
+recirc_id(0),in_port(5),eth(dst=aa:55:00:00:00:02),eth_type(0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,frag=no), packets:1, bytes:136, used:0.0s, actions:set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(10)
+recirc_id(0),in_port(7),eth(dst=aa:55:00:00:00:02),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:136, used:0.0s, actions:8
+tunnel(src=20.0.0.1,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(10),packet_type(ns=0,id=0x0),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)),12
+])
+
+# Clear up megaflow cache
+ovs-appctl time/warp 11000
+
+# N2 to N1 via the L2 GRE tunnel between br-in2 and br-in1
+AT_CHECK([
+    ovs-appctl netdev-dummy/receive n2 3a6dd2099cab461e7d1a95a10800450000542c1f40004001791bc0a80a14c0a80a0a0800154b0b6800011b519a580000000054cf0e0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+    ovs-appctl netdev-dummy/receive n2 3a6dd2099cab461e7d1a95a10800450000542c744000400178c6c0a80a14c0a80a0a08003f420b6800021c519a580000000029d70e0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+], [0], [ignore])
+
+ovs-appctl time/warp 1000
+
+AT_CHECK([
+    ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+], [0], [flow-dump from non-dpdk interfaces:
+recirc_id(0),in_port(12),packet_type(ns=0,id=0x0),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(10),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(2))
+recirc_id(0),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:136, used:0.0s, actions:5
+recirc_id(0),in_port(4),eth(dst=aa:55:00:00:00:01),eth_type(0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,frag=no), packets:1, bytes:136, used:0.0s, actions:set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(10)
+recirc_id(0),in_port(8),eth(dst=aa:55:00:00:00:01),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:136, used:0.0s, actions:7
+tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(10),packet_type(ns=0,id=0x0),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)),11
+])
+
+# Clear up megaflow cache
+ovs-appctl time/warp 11000
+
+# N2 to N3 via br-in1 using the L2 GRE tunnel between br-in2 and br-in1 and the L2 GRE tunnel between br-in1 and br-in3
+AT_CHECK([
+    ovs-appctl netdev-dummy/receive n2 1e2ce92a669e461e7d1a95a1080045000054f7d440004001ad51c0a80a14c0a80a1e08000e760c1e000131519a580000000047ee0b0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+    ovs-appctl netdev-dummy/receive n2 1e2ce92a669e461e7d1a95a1080045000054f89540004001ac90c0a80a14c0a80a1e0800736f0c1e000232519a5800000000e1f30b0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+], [0], [ignore])
+
+ovs-appctl time/warp 1000
+
+AT_CHECK([
+    ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+], [0], [flow-dump from non-dpdk interfaces:
+recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:136, used:0.0s, actions:4
+recirc_id(0),in_port(12),packet_type(ns=0,id=0x0),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(10),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(2))
+recirc_id(0),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:136, used:0.0s, actions:5
+recirc_id(0),in_port(4),eth(dst=aa:55:00:00:00:01),eth_type(0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,frag=no), packets:1, bytes:136, used:0.0s, actions:set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(10)
+recirc_id(0),in_port(6),eth(dst=aa:55:00:00:00:03),eth_type(0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,frag=no), packets:1, bytes:136, used:0.0s, actions:set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(10)
+recirc_id(0),in_port(7),eth(dst=aa:55:00:00:00:03),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:136, used:0.0s, actions:9
+recirc_id(0),in_port(8),eth(dst=aa:55:00:00:00:01),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:136, used:0.0s, actions:7
+tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(10),packet_type(ns=0,id=0x0),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(10),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(1))
+tunnel(src=30.0.0.1,dst=30.0.0.3,flags(-df-csum)),recirc_id(0),in_port(10),packet_type(ns=0,id=0x0),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)),13
+])
+
+# Clear up megaflow cache
+ovs-appctl time/warp 11000
+
+# N3 to N1 via br-in2 using the L3 GRE tunnel between br-in3 and br-in2 and the L3 GRE tunnel between br-in2 and br-in1
+AT_CHECK([
+    ovs-appctl netdev-dummy/receive n3 3a6dd2099cab1e2ce92a669e080045000054b80440004001ed2bc0a80a1ec0a80a0a0800e17a77d5015e64509a5800000000d3d50c0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+    ovs-appctl netdev-dummy/receive n3 3a6dd2099cab1e2ce92a669e080045000054b8a240004001ec8dc0a80a1ec0a80a0a0800627177d5015f65509a580000000051de0c0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+], [0], [ignore])
+
+ovs-appctl time/warp 1000
+
+AT_CHECK([
+    ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+], [0], [flow-dump from non-dpdk interfaces:
+recirc_id(0),in_port(13),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(10),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(3))
+recirc_id(0),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:122, used:0.0s, actions:5
+recirc_id(0),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:122, used:0.0s, actions:6
+recirc_id(0),in_port(4),eth(dst=aa:55:00:00:00:01),eth_type(0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,frag=no), packets:1, bytes:122, used:0.0s, actions:set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(10)
+recirc_id(0),in_port(5),eth(dst=aa:55:00:00:00:02),eth_type(0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,frag=no), packets:1, bytes:122, used:0.0s, actions:set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(10)
+recirc_id(0),in_port(8),eth(dst=aa:55:00:00:00:01),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:122, used:0.0s, actions:7
+recirc_id(0),in_port(9),eth(dst=aa:55:00:00:00:02),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:122, used:0.0s, actions:8
+tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(10),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),11
+tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(10),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(10),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(2))
+])
+
+# Clear up megaflow cache
+ovs-appctl time/warp 11000
+
+# N3 to N2 via L3 GRE tunnel between br-in3 and br-in2
+AT_CHECK([
+    ovs-appctl netdev-dummy/receive n3 461e7d1a95a11e2ce92a669e080045000054e5b540004001bf70c0a80a1ec0a80a140800b3f1065b000188509a580000000050360c0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+    ovs-appctl netdev-dummy/receive n3 461e7d1a95a11e2ce92a669e080045000054e5cf40004001bf56c0a80a1ec0a80a140800a2ed065b000289509a580000000060390c0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+], [0], [ignore])
+
+ovs-appctl time/warp 1000
+
+AT_CHECK([
+    ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+], [0], [flow-dump from non-dpdk interfaces:
+recirc_id(0),in_port(13),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(10),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(3))
+recirc_id(0),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:136, used:0.0s, actions:6
+recirc_id(0),in_port(5),eth(dst=aa:55:00:00:00:02),eth_type(0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,frag=no), packets:1, bytes:136, used:0.0s, actions:set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(10)
+recirc_id(0),in_port(9),eth(dst=aa:55:00:00:00:02),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:136, used:0.0s, actions:8
+tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(10),packet_type(ns=0,id=0x0),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)),12
+])
+
+### Check the received packets
+
+AT_CHECK([
+    ovs-pcap n1.pcap
+], [0], [dnl
+aa55aa550001461e7d1a95a10800450000542c1f40004001791bc0a80a14c0a80a0a0800154b0b6800011b519a580000000054cf0e0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+aa55aa550001461e7d1a95a10800450000542c744000400178c6c0a80a14c0a80a0a08003f420b6800021c519a580000000029d70e0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+aa55aa550001000000000000080045000054b80440004001ed2bc0a80a1ec0a80a0a0800e17a77d5015e64509a5800000000d3d50c0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+aa55aa550001000000000000080045000054b8a240004001ec8dc0a80a1ec0a80a0a0800627177d5015f65509a580000000051de0c0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+])
+
+AT_CHECK([
+    ovs-pcap n2.pcap
+], [0], [dnl
+aa55aa5500023a6dd2099cab080045000054500b40004001552fc0a80a0ac0a80a140800531f09a90001e9509a580000000055ba030000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+aa55aa5500023a6dd2099cab08004500005450934000400154a7c0a80a0ac0a80a140800f41d09a90002ea509a5800000000b3ba030000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+aa55aa5500021e2ce92a669e080045000054e5b540004001bf70c0a80a1ec0a80a140800b3f1065b000188509a580000000050360c0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+aa55aa5500021e2ce92a669e080045000054e5cf40004001bf56c0a80a1ec0a80a140800a2ed065b000289509a580000000060390c0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+])
+
+AT_CHECK([
+    ovs-pcap n3.pcap
+], [0], [dnl
+aa55aa5500033a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+aa55aa5500033a6dd2099cab0800450000548a83400040011aadc0a80a0ac0a80a1e0800b7170a4d0002fd509a5800000000de1c020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+aa55aa550003461e7d1a95a1080045000054f7d440004001ad51c0a80a14c0a80a1e08000e760c1e000131519a580000000047ee0b0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+aa55aa550003461e7d1a95a1080045000054f89540004001ac90c0a80a14c0a80a1e0800736f0c1e000232519a5800000000e1f30b0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+])
+
+OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
+AT_CLEANUP
diff --git a/tests/system-userspace-packet-type-aware.at b/tests/system-userspace-packet-type-aware.at
new file mode 100644
index 0000000..0d84415
--- /dev/null
+++ b/tests/system-userspace-packet-type-aware.at
@@ -0,0 +1,422 @@
+AT_BANNER([packet-type-aware pipeline])
+
+AT_SETUP([ptap - triangle bridge setup with L2 and L3 GRE tunnels])
+
+########################
+# GRE tunneling test setup for PTAP bridge
+#
+#     192.168.10.10           192.168.10.20             192.168.10.30
+#          n1                       n2                        n3
+#          |ovs-n1                  |ovs-n2                   |ovs-n3
+#   +------o------+          +------o------+           +------o------+
+#   |    br-in1   |          |    br-in2   |           |    br-in3   |
+#   |             |          |   (PTAP)    |           |             |
+#   +------o------+          +------o------+           +------o------+
+#         gre                      gre                       gre
+#   10.0.0.1                (10.0.0.2)                (10.0.0.3)
+#  (20.0.0.1)                20.0.0.2                 (20.0.0.3)
+#  (30.0.0.1) LOCAL         (30.0.0.2) LOCAL           30.0.0.3  LOCAL
+#   +-----------o-+          +-----------o-+           +-----------o-+
+#   |    br-p1    |          |    br-p2    |           |    br-p3    |
+#   +------o------+          +------o------+           +------o------+
+#     p1-0 |                        | p2-0                    | p3-0
+#     p0-1 |                        | p0-2                    | p0-3
+#       +--o------------------------o-------------------------o--+
+#       |                          br0                           |
+#       +--------------------------------------------------------+
+#"
+#   GRE tunnel ports:
+#      No     Bridge      Name        Type        Remote bridge & ports
+#     -----------------------------------------------------------------------
+#      1020   br-in1      gre-12      l2          br-in2 2010 (versatile)
+#      1021   br-in1      gre-12_l3   l3                same
+#      1030   br-in1      gre-13      l2          br-in3 3010 (l2)
+#      2010   br-in2      gre-21      versatile   br-in1 1020 (l2), 1021 (l3)
+#      2030   br-in2      gre-13      versatile   br-in3 3020 (l2), 3021 (l3)
+#      3010   br-in1      gre-31      l2          br-in1 1030 (l2)
+#      3020   br-in1      gre-32      l2          br-in2 2010 (versatile)
+#      3021   br-in1      gre-32_l3   l3                same
+
+
+AT_SKIP_IF([test $HAVE_NC = no])
+OVS_TRAFFIC_VSWITCHD_START()
+
+HWADDR_BRP1=aa:55:00:00:00:01
+HWADDR_BRP2=aa:55:00:00:00:02
+HWADDR_BRP3=aa:55:00:00:00:03
+
+dnl Create veth ports to connect br0 with br-p1, br-p2 and br-p3
+AT_CHECK([ip link add p1-0 type veth peer name p0-1])
+AT_CHECK([ip link set p1-0 up])
+AT_CHECK([ip link set p0-1 up])
+AT_CHECK([ip link set dev p1-0 mtu 3300])
+AT_CHECK([ip link set dev p0-1 mtu 3300])
+on_exit 'ip link del p0-1'
+
+AT_CHECK([ip link add p2-0 type veth peer name p0-2])
+AT_CHECK([ip link set p2-0 up])
+AT_CHECK([ip link set p0-2 up])
+AT_CHECK([ip link set dev p2-0 mtu 3300])
+AT_CHECK([ip link set dev p0-2 mtu 3300])
+on_exit 'ip link del p0-2'
+
+AT_CHECK([ip link add p3-0 type veth peer name p0-3])
+AT_CHECK([ip link set p3-0 up])
+AT_CHECK([ip link set p0-3 up])
+AT_CHECK([ip link set dev p3-0 mtu 3300])
+AT_CHECK([ip link set dev p0-3 mtu 3300])
+on_exit 'ip link del p0-3'
+
+# Setup bridge infrastructure
+AT_CHECK([
+    ovs-vsctl add-br br-in1 -- \
+        set bridge br-in1 datapath_type=netdev fail-mode=standalone
+    ovs-vsctl add-br br-in2 -- \
+        set bridge br-in2 datapath_type=netdev fail-mode=standalone other-config:packet-type-aware=true
+    ovs-vsctl add-br br-in3 -- \
+        set bridge br-in3 datapath_type=netdev fail-mode=standalone
+    ovs-vsctl add-br br-p1 -- \
+        set bridge br-p1 datapath_type=netdev fail-mode=standalone other-config:hwaddr=$HWADDR_BRP1
+    ovs-vsctl add-br br-p2 -- \
+        set bridge br-p2 datapath_type=netdev fail-mode=standalone other-config:hwaddr=$HWADDR_BRP2
+    ovs-vsctl add-br br-p3 -- \
+        set bridge br-p3 datapath_type=netdev fail-mode=standalone other-config:hwaddr=$HWADDR_BRP3
+
+    ovs-vsctl add-port br-p1 p1-0 -- set interface p1-0 ofport_request=2
+    ovs-vsctl add-port br-p2 p2-0 -- set interface p2-0 ofport_request=2
+    ovs-vsctl add-port br-p3 p3-0 -- set interface p3-0 ofport_request=2
+    ovs-vsctl add-port br0 p0-1 -- set interface p0-1 ofport_request=10
+    ovs-vsctl add-port br0 p0-2 -- set interface p0-2 ofport_request=20
+    ovs-vsctl add-port br0 p0-3 -- set interface p0-3 ofport_request=30
+
+    # Populate the MAC table of br0
+    ovs-ofctl del-flows br0
+    ovs-ofctl add-flow br0 dl_dst=$HWADDR_BRP1,actions=10
+    ovs-ofctl add-flow br0 dl_dst=$HWADDR_BRP2,actions=20
+    ovs-ofctl add-flow br0 dl_dst=$HWADDR_BRP3,actions=30
+
+    ovs-ofctl del-flows br-in1
+    ovs-ofctl del-flows br-in2
+    ovs-ofctl del-flows br-in3
+    ovs-ofctl del-flows br-p1
+    ovs-ofctl del-flows br-p2
+    ovs-ofctl del-flows br-p3
+], [0])
+
+# Get the MAC addresses of the tunnel end-point ports
+#HWADDR_BRP1=$(ovs-ofctl show br-p1 | grep LOCAL | sed 's/.*addr://')
+#HWADDR_BRP2=$(ovs-ofctl show br-p2 | grep LOCAL | sed 's/.*addr://')
+#HWADDR_BRP3=$(ovs-ofctl show br-p3 | grep LOCAL | sed 's/.*addr://')
+
+### Setup GRE tunnels
+AT_CHECK([
+    ovs-vsctl add-port br-in1 gre12 -- \
+        set interface gre12 type=gre options:remote_ip=10.0.0.2 ofport_request=1020
+    ovs-vsctl add-port br-in1 gre12_l3 -- \
+        set interface gre12_l3 type=gre options:remote_ip=10.0.0.2 ofport_request=1021 options:layer3=true
+    ovs-vsctl add-port br-in1 gre13 -- \
+        set interface gre13 type=gre options:remote_ip=10.0.0.3 ofport_request=1030
+
+    ovs-vsctl add-port br-in2 gre21 -- \
+        set interface gre21 type=gre options:remote_ip=20.0.0.1 ofport_request=2010
+    ovs-vsctl add-port br-in2 gre23 -- \
+        set interface gre23 type=gre options:remote_ip=20.0.0.3 ofport_request=2030
+
+    ovs-vsctl add-port br-in3 gre31 -- \
+        set interface gre31 type=gre options:remote_ip=30.0.0.1 ofport_request=3010
+    ovs-vsctl add-port br-in3 gre32 -- \
+        set interface gre32 type=gre options:remote_ip=30.0.0.2 ofport_request=3020
+    ovs-vsctl add-port br-in3 gre32_l3 -- \
+        set interface gre32_l3 type=gre options:remote_ip=30.0.0.2 ofport_request=3021 options:layer3=true
+], [0], [stdout])
+
+AT_CHECK([
+    ip addr add 10.0.0.1/24 dev br-p1
+    ip link set br-p1 up
+], [0], [stdout])
+
+AT_CHECK([
+    ovs-appctl ovs/route/add 10.0.0.0/24 br-p1
+    ovs-appctl tnl/arp/set br-p1 10.0.0.1 $HWADDR_BRP1
+    ovs-appctl tnl/arp/set br-p1 10.0.0.2 $HWADDR_BRP2
+    ovs-appctl tnl/arp/set br-p1 10.0.0.3 $HWADDR_BRP3
+], [0], [stdout])
+
+AT_CHECK([
+    ip addr add 20.0.0.2/24 dev br-p2
+    ip link set br-p2 up
+], [0], [stdout])
+
+AT_CHECK([
+    ovs-appctl ovs/route/add 20.0.0.0/24 br-p2
+    ovs-appctl tnl/arp/set br-p2 20.0.0.1 $HWADDR_BRP1
+    ovs-appctl tnl/arp/set br-p2 20.0.0.2 $HWADDR_BRP2
+    ovs-appctl tnl/arp/set br-p2 20.0.0.3 $HWADDR_BRP3
+], [0], [stdout])
+
+AT_CHECK([
+    ip addr add 30.0.0.3/24 dev br-p3
+    ip link set br-p3 up
+], [0], [stdout])
+
+AT_CHECK([
+    ovs-appctl ovs/route/add 30.0.0.0/24 br-p3
+    ovs-appctl tnl/arp/set br-p3 30.0.0.1 $HWADDR_BRP1
+    ovs-appctl tnl/arp/set br-p3 30.0.0.2 $HWADDR_BRP2
+    ovs-appctl tnl/arp/set br-p3 30.0.0.3 $HWADDR_BRP3
+], [0], [stdout])
+
+AT_CHECK([
+    ovs-appctl ovs/route/show | grep User:
+], [0], [dnl
+User: 10.0.0.0/24 dev br-p1 SRC 10.0.0.1
+User: 20.0.0.0/24 dev br-p2 SRC 20.0.0.2
+User: 30.0.0.0/24 dev br-p3 SRC 30.0.0.3
+])
+
+AT_CHECK([
+    ovs-appctl tnl/neigh/show | grep br-p | sort
+], [0], [stdout])
+
+
+### Flows in br-p<x>to twist TEP IP addresses in tunnel IP headers
+AT_CHECK([
+    ovs-ofctl add-flow br-p1 in_port:LOCAL,actions=2
+    ovs-ofctl add-flow br-p1 in_port:2,ip,nw_dst:20.0.0.1,actions=mod_nw_dst:10.0.0.1,mod_nw_src:10.0.0.2,LOCAL
+    ovs-ofctl add-flow br-p1 in_port:2,ip,nw_dst:30.0.0.1,actions=mod_nw_dst:10.0.0.1,mod_nw_src:10.0.0.3,LOCAL
+
+    ovs-ofctl add-flow br-p2 in_port:LOCAL,actions=2
+    ovs-ofctl add-flow br-p2 in_port:2,ip,nw_dst:10.0.0.2,actions=mod_nw_dst:20.0.0.2,mod_nw_src:20.0.0.1,LOCAL
+    ovs-ofctl add-flow br-p2 in_port:2,ip,nw_dst:30.0.0.2,actions=mod_nw_dst:20.0.0.2,mod_nw_src:20.0.0.3,LOCAL
+
+    ovs-ofctl add-flow br-p3 in_port:LOCAL,actions=2
+    ovs-ofctl add-flow br-p3 in_port:2,ip,nw_dst:10.0.0.3,actions=mod_nw_dst:30.0.0.3,mod_nw_src:30.0.0.1,LOCAL
+    ovs-ofctl add-flow br-p3 in_port:2,ip,nw_dst:20.0.0.3,actions=mod_nw_dst:30.0.0.3,mod_nw_src:30.0.0.2,LOCAL
+], [0])
+
+# Strips 'n_packets=...' from ovs-ofctl output.
+strip_n_packets () {
+    sed 's/n_packets=[[0-9]]*, //'
+}
+
+# Strips 'n_bytes=...' from ovs-ofctl output.
+strip_n_bytes () {
+    sed 's/n_bytes=[[0-9]]*, //'
+}
+
+AT_CHECK([
+    ovs-ofctl dump-flows br-p1 | ofctl_strip | strip_n_packets | strip_n_bytes | sort | grep actions
+    ovs-ofctl dump-flows br-p2 | ofctl_strip | strip_n_packets | strip_n_bytes | sort | grep actions
+    ovs-ofctl dump-flows br-p3 | ofctl_strip | strip_n_packets | strip_n_bytes | sort | grep actions
+], [0], [dnl
+ in_port=LOCAL actions=output:2
+ ip,in_port=2,nw_dst=20.0.0.1 actions=mod_nw_dst:10.0.0.1,mod_nw_src:10.0.0.2,LOCAL
+ ip,in_port=2,nw_dst=30.0.0.1 actions=mod_nw_dst:10.0.0.1,mod_nw_src:10.0.0.3,LOCAL
+ in_port=LOCAL actions=output:2
+ ip,in_port=2,nw_dst=10.0.0.2 actions=mod_nw_dst:20.0.0.2,mod_nw_src:20.0.0.1,LOCAL
+ ip,in_port=2,nw_dst=30.0.0.2 actions=mod_nw_dst:20.0.0.2,mod_nw_src:20.0.0.3,LOCAL
+ in_port=LOCAL actions=output:2
+ ip,in_port=2,nw_dst=10.0.0.3 actions=mod_nw_dst:30.0.0.3,mod_nw_src:30.0.0.1,LOCAL
+ ip,in_port=2,nw_dst=20.0.0.3 actions=mod_nw_dst:30.0.0.3,mod_nw_src:30.0.0.2,LOCAL
+])
+
+### Setup test ports for traffic injection
+N1_IP=192.168.10.10
+N2_IP=192.168.10.20
+N3_IP=192.168.10.30
+N1_MAC=aa:55:aa:55:00:01
+N2_MAC=aa:55:aa:55:00:02
+N3_MAC=aa:55:aa:55:00:03
+N1_OFPORT=10
+N2_OFPORT=20
+N3_OFPORT=30
+
+ADD_NAMESPACES(ns1, ns2, ns3)
+ADD_VETH(n1, ns1, br-in1, "$N1_IP/24", $N1_MAC)
+ADD_VETH(n2, ns2, br-in2, "$N2_IP/24", $N2_MAC)
+ADD_VETH(n3, ns3, br-in3, "$N3_IP/24", $N3_MAC)
+
+NS_EXEC([ns1], [arp -s $N2_IP $N2_MAC])
+NS_EXEC([ns1], [arp -s $N3_IP $N3_MAC])
+
+NS_EXEC([ns2], [arp -s $N1_IP $N1_MAC])
+NS_EXEC([ns2], [arp -s $N3_IP $N3_MAC])
+
+NS_EXEC([ns3], [arp -s $N2_IP $N2_MAC])
+NS_EXEC([ns3], [arp -s $N1_IP $N1_MAC])
+
+AT_CHECK([
+    ovs-vsctl set interface ovs-n1 ofport_request=$N1_OFPORT
+    ovs-vsctl set interface ovs-n2 ofport_request=$N2_OFPORT
+    ovs-vsctl set interface ovs-n3 ofport_request=$N3_OFPORT
+], [0])
+
+#N1_DPPORT=$(ovs-appctl dpif/show | grep "n1 10" | sed 's|.*/\([[0-9]]*\):.*|\1|')
+#N2_DPPORT=$(ovs-appctl dpif/show | grep "n2 20" | sed 's|.*/\([[0-9]]*\):.*|\1|')
+#N3_DPPORT=$(ovs-appctl dpif/show | grep "n3 30" | sed 's|.*/\([[0-9]]*\):.*|\1|')
+
+### Verify datapath configuration
+AT_CHECK([
+    ovs-appctl dpif/show | grep -v hit | sed 's/\t/    /g'
+], [0], [dnl
+    br-in1:
+        br-in1 65534/2: (tap)
+        gre12 1020/14: (gre: remote_ip=10.0.0.2)
+        gre12_l3 1021/14: (gre: layer3=true, remote_ip=10.0.0.2)
+        gre13 1030/14: (gre: remote_ip=10.0.0.3)
+        ovs-n1 10/15: (system)
+    br-in2:
+        br-in2 65534/3: (tap)
+        gre21 2010/14: (gre: remote_ip=20.0.0.1)
+        gre23 2030/14: (gre: remote_ip=20.0.0.3)
+        ovs-n2 20/16: (system)
+    br-in3:
+        br-in3 65534/4: (tap)
+        gre31 3010/14: (gre: remote_ip=30.0.0.1)
+        gre32 3020/14: (gre: remote_ip=30.0.0.2)
+        gre32_l3 3021/14: (gre: layer3=true, remote_ip=30.0.0.2)
+        ovs-n3 30/17: (system)
+    br-p1:
+        br-p1 65534/5: (tap)
+        p1-0 2/8: (system)
+    br-p2:
+        br-p2 65534/6: (tap)
+        p2-0 2/9: (system)
+    br-p3:
+        br-p3 65534/7: (tap)
+        p3-0 2/10: (system)
+    br0:
+        br0 65534/1: (tap)
+        p0-1 10/11: (system)
+        p0-2 20/12: (system)
+        p0-3 30/13: (system)
+])
+
+### Test L3 forwarding flows
+AT_CHECK([
+    ovs-ofctl add-flow br-in1 ip,nw_dst=$N1_IP,actions=mod_dl_dst:$N1_MAC,$N1_OFPORT # Local route to N1
+    ovs-ofctl add-flow br-in1 ip,nw_dst=$N2_IP,actions=1020 # Route to N2 via the L2 tunnel to br-in2
+    ovs-ofctl add-flow br-in1 ip,nw_dst=$N3_IP,actions=1030 # Route to N3 direct through L2 tunnel
+
+    ovs-ofctl add-flow br-in2 ip,nw_dst=$N2_IP,actions=mod_dl_dst:$N2_MAC,$N2_OFPORT # Local route to N2 for ethernet packets
+    ovs-ofctl add-flow br-in2 ip,nw_dst=$N1_IP,actions=2010 # Route to N1 for ethernet packet
+    ovs-ofctl add-flow br-in2 packet_type=\(1,0x800\),nw_dst=$N1_IP,actions=2010 # Route to N1 for IP packets
+    ovs-ofctl add-flow br-in2 ip,nw_dst=$N3_IP,actions=2010 # Indirect route to N3 via br-in1 for ethernet packet
+    ovs-ofctl add-flow br-in2 packet_type=\(1,0x800\),nw_dst=$N3_IP,actions=2030 # Direct route to N3 for IP packets
+
+    ovs-ofctl add-flow br-in3 ip,nw_dst=$N3_IP,actions=mod_dl_dst:$N3_MAC,$N3_OFPORT # Local route to N1
+    ovs-ofctl add-flow br-in3 ip,nw_dst=$N2_IP,actions=3020 # Route to N2 via the L2 tunnel
+    ovs-ofctl add-flow br-in3 ip,nw_dst=$N1_IP,actions=3021 # Route to N1 via br-in2 through L3 tunnel
+], [0])
+
+AT_CHECK([
+    ovs-ofctl dump-flows br-in1 | ofctl_strip | strip_n_packets | strip_n_bytes | sort | grep actions
+], [0], [dnl
+ ip,nw_dst=192.168.10.10 actions=mod_dl_dst:aa:55:aa:55:00:01,output:10
+ ip,nw_dst=192.168.10.20 actions=output:1020
+ ip,nw_dst=192.168.10.30 actions=output:1030
+])
+
+AT_CHECK([
+    ovs-ofctl dump-flows br-in2 | ofctl_strip | strip_n_packets | strip_n_bytes | sort | grep actions
+], [0], [dnl
+ packet_type=(0,0x0),ip,nw_dst=192.168.10.10 actions=output:2010
+ packet_type=(0,0x0),ip,nw_dst=192.168.10.20 actions=mod_dl_dst:aa:55:aa:55:00:02,output:20
+ packet_type=(0,0x0),ip,nw_dst=192.168.10.30 actions=output:2010
+ packet_type=(1,0x800),nw_dst=192.168.10.10 actions=output:2010
+ packet_type=(1,0x800),nw_dst=192.168.10.30 actions=output:2030
+])
+
+AT_CHECK([
+    ovs-ofctl dump-flows br-in3 | ofctl_strip | strip_n_packets | strip_n_bytes | sort | grep actions
+], [0], [dnl
+ ip,nw_dst=192.168.10.10 actions=output:3021
+ ip,nw_dst=192.168.10.20 actions=output:3020
+ ip,nw_dst=192.168.10.30 actions=mod_dl_dst:aa:55:aa:55:00:03,output:30
+])
+
+
+# Clear up megaflow cache
+
+# Ping between N1 and N3, via the L2 GRE tunnel between br-in1 and br-in3
+NS_CHECK_EXEC([ns1], [ping -q -c 3 -i 0.3 -w 2 $N3_IP | FORMAT_PING], [0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+sleep 1
+
+AT_CHECK([
+    ovs-appctl dpctl/dump-flows | strip_used | grep -v ipv6 | grep -v arp |sort
+], [0], [flow-dump from non-dpdk interfaces:
+recirc_id(0),in_port(10),eth(dst=aa:55:00:00:00:03),eth_type(0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,frag=no), packets:2, bytes:272, used:0.0s, actions:set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(14)
+recirc_id(0),in_port(11),eth(dst=aa:55:00:00:00:03),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:272, used:0.0s, actions:13
+recirc_id(0),in_port(12),eth(dst=aa:55:00:00:00:01),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:244, used:0.0s, actions:11
+recirc_id(0),in_port(13),eth(dst=aa:55:00:00:00:02),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:244, used:0.0s, actions:12
+recirc_id(0),in_port(15),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no), packets:2, bytes:196, used:0.0s, actions:tnl_push(tnl_port(14),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(5))
+recirc_id(0),in_port(17),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:2, bytes:196, used:0.0s, actions:pop_eth,tnl_push(tnl_port(14),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(7))
+recirc_id(0),in_port(5),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:272, used:0.0s, actions:8
+recirc_id(0),in_port(6),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:244, used:0.0s, actions:9
+recirc_id(0),in_port(7),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:244, used:0.0s, actions:10
+recirc_id(0),in_port(8),eth(dst=aa:55:00:00:00:01),eth_type(0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,frag=no), packets:2, bytes:244, used:0.0s, actions:set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(14)
+recirc_id(0),in_port(9),eth(dst=aa:55:00:00:00:02),eth_type(0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,frag=no), packets:2, bytes:244, used:0.0s, actions:set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(14)
+tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(14),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,frag=no), packets:2, bytes:168, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:01),15
+tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(14),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:2, bytes:168, used:0.0s, actions:tnl_push(tnl_port(14),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(6))
+tunnel(src=30.0.0.1,dst=30.0.0.3,flags(-df-csum)),recirc_id(0),in_port(14),packet_type(ns=0,id=0x0),eth(dst=aa:55:aa:55:00:03),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no), packets:2, bytes:196, used:0.0s, actions:17
+])
+
+# Clear up megaflow cache
+sleep 10
+
+# Ping between N1 and N2, via the L2 GRE tunnel between br-in1 and br-in2
+NS_CHECK_EXEC([ns1], [ping -q -c 3 -i 0.3 -w 2 $N2_IP | FORMAT_PING], [0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+sleep 1
+
+AT_CHECK([
+    ovs-appctl dpctl/dump-flows | strip_used | grep -v ipv6 | grep -v arp | sort
+], [0], [flow-dump from non-dpdk interfaces:
+recirc_id(0),in_port(11),eth(dst=aa:55:00:00:00:02),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:272, used:0.0s, actions:12
+recirc_id(0),in_port(12),eth(dst=aa:55:00:00:00:01),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:272, used:0.0s, actions:11
+recirc_id(0),in_port(15),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no), packets:2, bytes:196, used:0.0s, actions:tnl_push(tnl_port(14),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(5))
+recirc_id(0),in_port(16),packet_type(ns=0,id=0x0),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:2, bytes:196, used:0.0s, actions:tnl_push(tnl_port(14),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(6))
+recirc_id(0),in_port(5),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:272, used:0.0s, actions:8
+recirc_id(0),in_port(6),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:272, used:0.0s, actions:9
+recirc_id(0),in_port(8),eth(dst=aa:55:00:00:00:01),eth_type(0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,frag=no), packets:2, bytes:272, used:0.0s, actions:set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(14)
+recirc_id(0),in_port(9),eth(dst=aa:55:00:00:00:02),eth_type(0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,frag=no), packets:2, bytes:272, used:0.0s, actions:set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(14)
+tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(14),packet_type(ns=0,id=0x0),eth(dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(dst=192.168.10.10,frag=no), packets:2, bytes:196, used:0.0s, actions:15
+tunnel(src=20.0.0.1,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(14),packet_type(ns=0,id=0x0),eth(dst=aa:55:aa:55:00:02),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no), packets:2, bytes:196, used:0.0s, actions:16
+])
+
+# Clear up megaflow cache
+sleep 10
+
+# Ping between N3 and N2, via the L3 GRE tunnel between br-in3 and br-in2
+NS_CHECK_EXEC([ns3], [ping -q -c 3 -i 0.3 -w 2 $N1_IP | FORMAT_PING], [0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+sleep 1
+
+AT_CHECK([
+    ovs-appctl dpctl/dump-flows | strip_used | grep -v ipv6 | grep -v arp | sort
+], [0], [flow-dump from non-dpdk interfaces:
+recirc_id(0),in_port(10),eth(dst=aa:55:00:00:00:03),eth_type(0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,frag=no), packets:2, bytes:272, used:0.0s, actions:set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(14)
+recirc_id(0),in_port(11),eth(dst=aa:55:00:00:00:03),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:272, used:0.0s, actions:13
+recirc_id(0),in_port(12),eth(dst=aa:55:00:00:00:01),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:244, used:0.0s, actions:11
+recirc_id(0),in_port(13),eth(dst=aa:55:00:00:00:02),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:244, used:0.0s, actions:12
+recirc_id(0),in_port(15),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no), packets:2, bytes:196, used:0.0s, actions:tnl_push(tnl_port(14),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(5))
+recirc_id(0),in_port(17),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:2, bytes:196, used:0.0s, actions:pop_eth,tnl_push(tnl_port(14),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(7))
+recirc_id(0),in_port(5),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:272, used:0.0s, actions:8
+recirc_id(0),in_port(6),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:244, used:0.0s, actions:9
+recirc_id(0),in_port(7),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:244, used:0.0s, actions:10
+recirc_id(0),in_port(8),eth(dst=aa:55:00:00:00:01),eth_type(0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,frag=no), packets:2, bytes:244, used:0.0s, actions:set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(14)
+recirc_id(0),in_port(9),eth(dst=aa:55:00:00:00:02),eth_type(0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,frag=no), packets:2, bytes:244, used:0.0s, actions:set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(14)
+tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(14),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,frag=no), packets:2, bytes:168, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:01),15
+tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(14),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:2, bytes:168, used:0.0s, actions:tnl_push(tnl_port(14),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(6))
+tunnel(src=30.0.0.1,dst=30.0.0.3,flags(-df-csum)),recirc_id(0),in_port(14),packet_type(ns=0,id=0x0),eth(dst=aa:55:aa:55:00:03),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no), packets:2, bytes:196, used:0.0s, actions:17
+])
+
+OVS_TRAFFIC_VSWITCHD_STOP
+AT_CLEANUP
diff --git a/tests/system-userspace-testsuite.at b/tests/system-userspace-testsuite.at
index c99e512..e81f5a4 100644
--- a/tests/system-userspace-testsuite.at
+++ b/tests/system-userspace-testsuite.at
@@ -24,3 +24,4 @@ m4_include([tests/system-common-macros.at])
 
 m4_include([tests/system-traffic.at])
 m4_include([tests/system-ovn.at])
+m4_include([tests/system-userspace-packet-type-aware.at])
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 26f7357..c7febc6 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -77,3 +77,4 @@ m4_include([tests/ovn-sbctl.at])
 m4_include([tests/ovn-controller.at])
 m4_include([tests/ovn-controller-vtep.at])
 m4_include([tests/mcast-snooping.at])
+m4_include([tests/packet-type-aware.at])
