diff --git a/SOURCES/openvswitch-3.1.0.patch b/SOURCES/openvswitch-3.1.0.patch
index 3b0cda9..e15aa1d 100644
--- a/SOURCES/openvswitch-3.1.0.patch
+++ b/SOURCES/openvswitch-3.1.0.patch
@@ -3557,6 +3557,35 @@ index bbb31ef275..7054f8e745 100644
      for (i = 0; i < n_hooks; i++) {
          struct hook *h = &hooks[i];
          if (h->cancel_cb) {
+diff --git a/lib/flow.c b/lib/flow.c
+index c3a3aa3ce4..f0fea83c55 100644
+--- a/lib/flow.c
++++ b/lib/flow.c
+@@ -3355,6 +3355,24 @@ flow_compose(struct dp_packet *p, const struct flow *flow,
+             arp->ar_sha = flow->arp_sha;
+             arp->ar_tha = flow->arp_tha;
+         }
++    } else if (flow->dl_type == htons(ETH_TYPE_NSH)) {
++        struct nsh_hdr *nsh;
++
++        nsh = dp_packet_put_zeros(p, sizeof *nsh);
++        dp_packet_set_l3(p, nsh);
++
++        nsh_set_flags_ttl_len(nsh, flow->nsh.flags, flow->nsh.ttl,
++                              flow->nsh.mdtype == NSH_M_TYPE1
++                              ? NSH_M_TYPE1_LEN : NSH_BASE_HDR_LEN);
++        nsh->next_proto = flow->nsh.np;
++        nsh->md_type = flow->nsh.mdtype;
++        put_16aligned_be32(&nsh->path_hdr, flow->nsh.path_hdr);
++
++        if (flow->nsh.mdtype == NSH_M_TYPE1) {
++            for (size_t i = 0; i < 4; i++) {
++                put_16aligned_be32(&nsh->md1.context[i], flow->nsh.context[i]);
++            }
++        }
+     }
+ 
+     if (eth_type_mpls(flow->dl_type)) {
 diff --git a/lib/hash.c b/lib/hash.c
 index c722f3c3cc..3d574de9b4 100644
 --- a/lib/hash.c
@@ -3581,6 +3610,148 @@ index c722f3c3cc..3d574de9b4 100644
      }
  
      if (n) {
+diff --git a/lib/ipf.c b/lib/ipf.c
+index d452663743..1f22df98e0 100644
+--- a/lib/ipf.c
++++ b/lib/ipf.c
+@@ -504,13 +504,15 @@ ipf_reassemble_v6_frags(struct ipf_list *ipf_list)
+ }
+ 
+ /* Called when a frag list state transitions to another state. This is
+- * triggered by new fragment for the list being received.*/
+-static void
++* triggered by new fragment for the list being received. Returns a reassembled
++* packet if this fragment has completed one. */
++static struct reassembled_pkt *
+ ipf_list_state_transition(struct ipf *ipf, struct ipf_list *ipf_list,
+                           bool ff, bool lf, bool v6)
+     OVS_REQUIRES(ipf->ipf_lock)
+ {
+     enum ipf_list_state curr_state = ipf_list->state;
++    struct reassembled_pkt *ret = NULL;
+     enum ipf_list_state next_state;
+     switch (curr_state) {
+     case IPF_LIST_STATE_UNUSED:
+@@ -560,12 +562,15 @@ ipf_list_state_transition(struct ipf *ipf, struct ipf_list *ipf_list,
+                 ipf_reassembled_list_add(&ipf->reassembled_pkt_list, rp);
+                 ipf_expiry_list_remove(ipf_list);
+                 next_state = IPF_LIST_STATE_COMPLETED;
++                ret = rp;
+             } else {
+                 next_state = IPF_LIST_STATE_REASS_FAIL;
+             }
+         }
+     }
+     ipf_list->state = next_state;
++
++    return ret;
+ }
+ 
+ /* Some sanity checks are redundant, but prudent, in case code paths for
+@@ -797,7 +802,8 @@ ipf_is_frag_duped(const struct ipf_frag *frag_list, int last_inuse_idx,
+ static bool
+ ipf_process_frag(struct ipf *ipf, struct ipf_list *ipf_list,
+                  struct dp_packet *pkt, uint16_t start_data_byte,
+-                 uint16_t end_data_byte, bool ff, bool lf, bool v6)
++                 uint16_t end_data_byte, bool ff, bool lf, bool v6,
++                 struct reassembled_pkt **rp)
+     OVS_REQUIRES(ipf->ipf_lock)
+ {
+     bool duped_frag = ipf_is_frag_duped(ipf_list->frag_list,
+@@ -818,7 +824,7 @@ ipf_process_frag(struct ipf *ipf, struct ipf_list *ipf_list,
+             ipf_list->last_inuse_idx++;
+             atomic_count_inc(&ipf->nfrag);
+             ipf_count(ipf, v6, IPF_NFRAGS_ACCEPTED);
+-            ipf_list_state_transition(ipf, ipf_list, ff, lf, v6);
++            *rp = ipf_list_state_transition(ipf, ipf_list, ff, lf, v6);
+         } else {
+             OVS_NOT_REACHED();
+         }
+@@ -851,7 +857,8 @@ ipf_list_init(struct ipf_list *ipf_list, struct ipf_list_key *key,
+  * to a list of fragemnts. */
+ static bool
+ ipf_handle_frag(struct ipf *ipf, struct dp_packet *pkt, ovs_be16 dl_type,
+-                uint16_t zone, long long now, uint32_t hash_basis)
++                uint16_t zone, long long now, uint32_t hash_basis,
++                struct reassembled_pkt **rp)
+     OVS_REQUIRES(ipf->ipf_lock)
+ {
+     struct ipf_list_key key;
+@@ -920,7 +927,7 @@ ipf_handle_frag(struct ipf *ipf, struct dp_packet *pkt, ovs_be16 dl_type,
+     }
+ 
+     return ipf_process_frag(ipf, ipf_list, pkt, start_data_byte,
+-                            end_data_byte, ff, lf, v6);
++                            end_data_byte, ff, lf, v6, rp);
+ }
+ 
+ /* Filters out fragments from a batch of fragments and adjust the batch. */
+@@ -939,11 +946,17 @@ ipf_extract_frags_from_batch(struct ipf *ipf, struct dp_packet_batch *pb,
+                           ||
+                           (dl_type == htons(ETH_TYPE_IPV6) &&
+                           ipf_is_valid_v6_frag(ipf, pkt)))) {
++            struct reassembled_pkt *rp = NULL;
+ 
+             ovs_mutex_lock(&ipf->ipf_lock);
+-            if (!ipf_handle_frag(ipf, pkt, dl_type, zone, now, hash_basis)) {
++            if (!ipf_handle_frag(ipf, pkt, dl_type, zone, now, hash_basis,
++                                 &rp)) {
+                 dp_packet_batch_refill(pb, pkt, pb_idx);
+             } else {
++                if (rp && !dp_packet_batch_is_full(pb)) {
++                    dp_packet_batch_refill(pb, rp->pkt, pb_idx);
++                    rp->list->reass_execute_ctx = rp->pkt;
++                }
+                 dp_packet_delete(pkt);
+             }
+             ovs_mutex_unlock(&ipf->ipf_lock);
+@@ -1061,6 +1074,9 @@ ipf_send_completed_frags(struct ipf *ipf, struct dp_packet_batch *pb,
+     struct ipf_list *ipf_list;
+ 
+     LIST_FOR_EACH_SAFE (ipf_list, list_node, &ipf->frag_complete_list) {
++        if ((ipf_list->key.dl_type == htons(ETH_TYPE_IPV6)) != v6) {
++            continue;
++        }
+         if (ipf_send_frags_in_list(ipf, ipf_list, pb, IPF_FRAG_COMPLETED_LIST,
+                                    v6, now)) {
+             ipf_completed_list_clean(&ipf->frag_lists, ipf_list);
+@@ -1094,6 +1110,9 @@ ipf_send_expired_frags(struct ipf *ipf, struct dp_packet_batch *pb,
+     size_t lists_removed = 0;
+ 
+     LIST_FOR_EACH_SAFE (ipf_list, list_node, &ipf->frag_exp_list) {
++        if ((ipf_list->key.dl_type == htons(ETH_TYPE_IPV6)) != v6) {
++            continue;
++        }
+         if (now <= ipf_list->expiration ||
+             lists_removed >= IPF_FRAG_LIST_MAX_EXPIRED) {
+             break;
+@@ -1114,7 +1133,8 @@ ipf_send_expired_frags(struct ipf *ipf, struct dp_packet_batch *pb,
+ /* Adds a reassmebled packet to a packet batch to be processed by the caller.
+  */
+ static void
+-ipf_execute_reass_pkts(struct ipf *ipf, struct dp_packet_batch *pb)
++ipf_execute_reass_pkts(struct ipf *ipf, struct dp_packet_batch *pb,
++                       ovs_be16 dl_type)
+ {
+     if (ovs_list_is_empty(&ipf->reassembled_pkt_list)) {
+         return;
+@@ -1125,6 +1145,7 @@ ipf_execute_reass_pkts(struct ipf *ipf, struct dp_packet_batch *pb)
+ 
+     LIST_FOR_EACH_SAFE (rp, rp_list_node, &ipf->reassembled_pkt_list) {
+         if (!rp->list->reass_execute_ctx &&
++            rp->list->key.dl_type == dl_type &&
+             ipf_dp_packet_batch_add(pb, rp->pkt, false)) {
+             rp->list->reass_execute_ctx = rp->pkt;
+         }
+@@ -1233,7 +1254,7 @@ ipf_preprocess_conntrack(struct ipf *ipf, struct dp_packet_batch *pb,
+     }
+ 
+     if (ipf_get_enabled(ipf) || atomic_count_get(&ipf->nfrag)) {
+-        ipf_execute_reass_pkts(ipf, pb);
++        ipf_execute_reass_pkts(ipf, pb, dl_type);
+     }
+ }
+ 
 diff --git a/lib/jhash.c b/lib/jhash.c
 index c59b51b611..a8e3f457b9 100644
 --- a/lib/jhash.c
@@ -13066,6 +13237,43 @@ index 600e85dabd..e0d4bed4f0 100644
 +
 +OVS_VSWITCHD_STOP
 +AT_CLEANUP
+diff --git a/tests/sendpkt.py b/tests/sendpkt.py
+index 49ac45275a..7cbea51654 100755
+--- a/tests/sendpkt.py
++++ b/tests/sendpkt.py
+@@ -48,28 +48,10 @@ if len(args) < 2:
+ if options.packet_type != "eth":
+     parser.error('invalid argument to "-t"/"--type". Allowed value is "eth".')
+ 
+-# store the hex bytes with 0x appended at the beginning
+-# if not present in the user input and validate the hex bytes
+-hex_list = []
+-for a in args[1:]:
+-    if a[:2] != "0x":
+-        hex_byte = "0x" + a
+-    else:
+-        hex_byte = a
+-    try:
+-        temp = int(hex_byte, 0)
+-    except:
+-        parser.error("invalid hex byte " + a)
+-
+-    if temp > 0xff:
+-        parser.error("hex byte " + a + " cannot be greater than 0xff!")
+-
+-    hex_list.append(temp)
+-
+-if sys.version_info < (3, 0):
+-    pkt = "".join(map(chr, hex_list))
+-else:
+-    pkt = bytes(hex_list)
++# Strip '0x' prefixes from hex input, combine into a single string and
++# convert to bytes.
++hex_str = "".join([a[2:] if a.startswith("0x") else a for a in args[1:]])
++pkt = bytes.fromhex(hex_str)
+ 
+ try:
+     sockfd = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
 diff --git a/tests/stp.at b/tests/stp.at
 index a6b6465d12..6239ec379f 100644
 --- a/tests/stp.at
@@ -14179,7 +14387,7 @@ index 871a3bda4f..3d84a53182 100644
  ])
  
 diff --git a/tests/system-traffic.at b/tests/system-traffic.at
-index 221d96aefb..7927f8e53c 100644
+index 221d96aefb..0dfc480e95 100644
 --- a/tests/system-traffic.at
 +++ b/tests/system-traffic.at
 @@ -10,13 +10,13 @@ ADD_NAMESPACES(at_ns0, at_ns1)
@@ -14779,7 +14987,7 @@ index 221d96aefb..7927f8e53c 100644
  10 packets transmitted, 10 received, 0% packet loss, time 0ms
  ])
  
-@@ -1987,6 +2064,57 @@ recirc_id(<recirc>),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:29, bytes
+@@ -1987,6 +2064,72 @@ recirc_id(<recirc>),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:29, bytes
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
  
@@ -14803,11 +15011,22 @@ index 221d96aefb..7927f8e53c 100644
 +AT_CHECK([ovs-ofctl del-flows br0])
 +AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
 +
++m4_define([ND_NS_PKT], [m4_join([,],
++  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x86dd],
++  [ipv6_src=fe80::f816:3eff:fe04:6604,ipv6_dst=fe80::f816:3eff:fea7:dd0e],
++  [nw_proto=58,nw_ttl=255,nw_frag=no],
++  [icmpv6_type=136,icmpv6_code=0],
++  [nd_options_type=2,nd_tll=36:b1:ee:7c:01:03])])
++
 +dnl Send a mismatching neighbor discovery.
-+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 86 dd 60 00 00 00 00 20 3a ff fe 80 00 00 00 00 00 00 f8 16 3e ff fe 04 66 04 fe 80 00 00 00 00 00 00 f8 16 3e ff fe a7 dd 0e 88 00 f1 f2 20 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 01 36 b1 ee 7c 01 03 > /dev/null])
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    $(ovs-ofctl compose-packet --bare 'ND_NS_PKT,nd_target=3000::1')],
++  [0], [ignore])
 +
 +dnl Send a matching neighbor discovery.
-+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 86 dd 60 00 00 00 00 20 3a ff fe 80 00 00 00 00 00 00 f8 16 3e ff fe 04 66 04 fe 80 00 00 00 00 00 00 f8 16 3e ff fe a7 dd 0e 88 00 fe 5f 20 00 00 00 20 01 00 00 00 00 00 00 00 00 00 01 00 00 03 92 02 01 36 b1 ee 7c 01 03 > /dev/null])
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    $(ovs-ofctl compose-packet --bare 'ND_NS_PKT,nd_target=2001::1:0:392')],
++  [0], [ignore])
 +
 +AT_CHECK([ovs-appctl dpctl/dump-flows | strip_stats | strip_used | dnl
 +          strip_key32 | strip_ptype | strip_eth | strip_recirc | dnl
@@ -14819,10 +15038,14 @@ index 221d96aefb..7927f8e53c 100644
 +OVS_WAIT_UNTIL([ovs-appctl dpctl/dump-flows | grep ",nd" | wc -l | grep -E ^0])
 +
 +dnl Send a matching neighbor discovery.
-+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 86 dd 60 00 00 00 00 20 3a ff fe 80 00 00 00 00 00 00 f8 16 3e ff fe 04 66 04 fe 80 00 00 00 00 00 00 f8 16 3e ff fe a7 dd 0e 88 00 fe 5f 20 00 00 00 20 01 00 00 00 00 00 00 00 00 00 01 00 00 03 92 02 01 36 b1 ee 7c 01 03 > /dev/null])
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    $(ovs-ofctl compose-packet --bare 'ND_NS_PKT,nd_target=2001::1:0:392')],
++  [0], [ignore])
 +
 +dnl Send a mismatching neighbor discovery.
-+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 86 dd 60 00 00 00 00 20 3a ff fe 80 00 00 00 00 00 00 f8 16 3e ff fe 04 66 04 fe 80 00 00 00 00 00 00 f8 16 3e ff fe a7 dd 0e 88 00 f1 f2 20 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 01 36 b1 ee 7c 01 03 > /dev/null])
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    $(ovs-ofctl compose-packet --bare 'ND_NS_PKT,nd_target=3000::1')],
++  [0], [ignore])
 +
 +AT_CHECK([ovs-appctl dpctl/dump-flows | strip_stats | strip_used | dnl
 +          strip_key32 | strip_ptype | strip_eth | strip_recirc | dnl
@@ -14837,7 +15060,263 @@ index 221d96aefb..7927f8e53c 100644
  AT_BANNER([MPLS])
  
  AT_SETUP([mpls - encap header dp-support])
-@@ -2343,6 +2471,7 @@ AT_CLEANUP
+@@ -2004,20 +2147,29 @@ dnl The flow will encap a mpls header to the ip packet
+ dnl eth/ip/icmp --> OVS --> eth/mpls/eth/ip/icmp
+ AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x0800 actions=encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,ovs-p1"])
+ 
+-rm -rf p1.pcap
+-NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
+-sleep 1
++NETNS_DAEMONIZE([at_ns1],
++  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
++OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
++
++m4_define([ICMP_PKT], [m4_join([,],
++  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x0800],
++  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
++  [nw_proto=1,nw_ttl=64,nw_frag=no],
++  [icmp_type=8,icmp_code=0])])
+ 
+-dnl The hex dump is a icmp packet. pkt=eth/ip/icmp
+ dnl The packet is sent from p0(at_ns0) interface directed to
+-dnl p1(at_ns1) interface
+-NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])
++dnl p1(at_ns1) interface.
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    $(ovs-ofctl compose-packet --bare 'ICMP_PKT')], [0], [ignore])
++
++dnl Check the expected mpls encapsulated packet on the egress interface.
++m4_define([MPLS_HEADER], [m4_join([,],
++  [eth_src=00:00:00:00:00:01,eth_dst=00:00:00:00:00:02,eth_type=0x8847],
++  [mpls_label=2,mpls_ttl=64,mpls_bos=1])])
+ 
+-dnl Check the expected mpls encapsulated packet on the egress interface
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000:  *0000 *0000 *0002 *0000 *0000 *0001 *8847 *0000" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010:  *2140 *36b1 *ee7c *0102 *36b1 *ee7c *0103 *0800" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020:  *4500 *0054 *0344 *4000 *4001 *2161 *0a01 *0101" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030:  *0a01 *0102 *0800 *efac *7ce4 *0003 *5b2c *1f61" 2>&1 1>/dev/null])
++OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
++    $(ovs-ofctl compose-packet --bare 'MPLS_HEADER'),
++    $(ovs-ofctl compose-packet --bare 'ICMP_PKT'), [\$])"])
+ 
+ OVS_TRAFFIC_VSWITCHD_STOP
+ AT_CLEANUP
+@@ -2036,20 +2188,29 @@ dnl The flow will encap a mpls header to the ip packet
+ dnl eth/ip/icmp --> OVS --> eth/mpls/eth/ip/icmp
+ AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x0800 actions=encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,ovs-p1"])
+ 
+-rm -rf p1.pcap
+-NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
+-sleep 1
++NETNS_DAEMONIZE([at_ns1],
++  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
++OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
++
++m4_define([ICMP_PKT], [m4_join([,],
++  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x0800],
++  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
++  [nw_proto=1,nw_ttl=64,nw_frag=no],
++  [icmp_type=8,icmp_code=0])])
+ 
+-dnl The hex dump is a icmp packet. pkt=eth/ip/icmp
+ dnl The packet is sent from p0(at_ns0) interface directed to
+-dnl p1(at_ns1) interface
+-NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])
++dnl p1(at_ns1) interface.
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    $(ovs-ofctl compose-packet --bare 'ICMP_PKT')], [0], [ignore])
++
++dnl Check the expected mpls encapsulated packet on the egress interface.
++m4_define([MPLS_HEADER], [m4_join([,],
++  [eth_src=00:00:00:00:00:01,eth_dst=00:00:00:00:00:02,eth_type=0x8847],
++  [mpls_label=2,mpls_ttl=64,mpls_bos=1])])
+ 
+-dnl Check the expected mpls encapsulated packet on the egress interface
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000:  *0000 *0000 *0002 *0000 *0000 *0001 *8847 *0000" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010:  *2140 *36b1 *ee7c *0102 *36b1 *ee7c *0103 *0800" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020:  *4500 *0054 *0344 *4000 *4001 *2161 *0a01 *0101" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030:  *0a01 *0102 *0800 *efac *7ce4 *0003 *5b2c *1f61" 2>&1 1>/dev/null])
++OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
++    $(ovs-ofctl compose-packet --bare 'MPLS_HEADER'),
++    $(ovs-ofctl compose-packet --bare 'ICMP_PKT'), [\$])"])
+ 
+ OVS_TRAFFIC_VSWITCHD_STOP
+ AT_CLEANUP
+@@ -2069,20 +2230,29 @@ dnl The flow will encap a mpls header to the ip packet
+ dnl eth/ip/icmp --> OVS --> eth/mpls/eth/ip/icmp
+ AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x0800 actions=encap(mpls_mc),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,ovs-p1"])
+ 
+-rm -rf p1.pcap
+-NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
+-sleep 1
++NETNS_DAEMONIZE([at_ns1],
++  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
++OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
++
++m4_define([ICMP_PKT], [m4_join([,],
++  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x0800],
++  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
++  [nw_proto=1,nw_ttl=64,nw_frag=no],
++  [icmp_type=8,icmp_code=0])])
+ 
+-dnl The hex dump is a icmp packet. pkt=eth/ip/icmp
+ dnl The packet is sent from p0(at_ns0) interface directed to
+-dnl p1(at_ns1) interface
+-NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])
++dnl p1(at_ns1) interface.
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    $(ovs-ofctl compose-packet --bare 'ICMP_PKT')], [0], [ignore])
++
++dnl Check the expected mpls encapsulated packet on the egress interface.
++m4_define([MPLS_HEADER], [m4_join([,],
++  [eth_src=00:00:00:00:00:01,eth_dst=00:00:00:00:00:02,eth_type=0x8848],
++  [mpls_label=2,mpls_ttl=64,mpls_bos=1])])
+ 
+-dnl Check the expected mpls encapsulated packet on the egress interface
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000:  *0000 *0000 *0002 *0000 *0000 *0001 *8848 *0000" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010:  *2140 *36b1 *ee7c *0102 *36b1 *ee7c *0103 *0800" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020:  *4500 *0054 *0344 *4000 *4001 *2161 *0a01 *0101" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030:  *0a01 *0102 *0800 *efac *7ce4 *0003 *5b2c *1f61" 2>&1 1>/dev/null])
++OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
++    $(ovs-ofctl compose-packet --bare 'MPLS_HEADER'),
++    $(ovs-ofctl compose-packet --bare 'ICMP_PKT'), [\$])"])
+ 
+ OVS_TRAFFIC_VSWITCHD_STOP
+ AT_CLEANUP
+@@ -2101,20 +2271,29 @@ dnl The flow will encap a mpls header to the ip packet
+ dnl eth/ip/icmp --> OVS --> eth/mpls/eth/ip/icmp
+ AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x0800 actions=encap(mpls_mc),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,ovs-p1"])
+ 
+-rm -rf p1.pcap
+-NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
+-sleep 1
++NETNS_DAEMONIZE([at_ns1],
++  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
++OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
++
++m4_define([ICMP_PKT], [m4_join([,],
++  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x0800],
++  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
++  [nw_proto=1,nw_ttl=64,nw_frag=no],
++  [icmp_type=8,icmp_code=0])])
+ 
+-dnl The hex dump is a icmp packet. pkt=eth/ip/icmp
+ dnl The packet is sent from p0(at_ns0) interface directed to
+-dnl p1(at_ns1) interface
+-NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])
++dnl p1(at_ns1) interface.
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    $(ovs-ofctl compose-packet --bare 'ICMP_PKT')], [0], [ignore])
++
++dnl Check the expected mpls encapsulated packet on the egress interface.
++m4_define([MPLS_HEADER], [m4_join([,],
++  [eth_src=00:00:00:00:00:01,eth_dst=00:00:00:00:00:02,eth_type=0x8848],
++  [mpls_label=2,mpls_ttl=64,mpls_bos=1])])
+ 
+-dnl Check the expected mpls encapsulated packet on the egress interface
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000:  *0000 *0000 *0002 *0000 *0000 *0001 *8848 *0000" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010:  *2140 *36b1 *ee7c *0102 *36b1 *ee7c *0103 *0800" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020:  *4500 *0054 *0344 *4000 *4001 *2161 *0a01 *0101" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030:  *0a01 *0102 *0800 *efac *7ce4 *0003 *5b2c *1f61" 2>&1 1>/dev/null])
++OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
++    $(ovs-ofctl compose-packet --bare 'MPLS_HEADER'),
++    $(ovs-ofctl compose-packet --bare 'ICMP_PKT'), [\$])"])
+ 
+ OVS_TRAFFIC_VSWITCHD_STOP
+ AT_CLEANUP
+@@ -2135,24 +2314,30 @@ dnl eth/mpls/eth/ip/icmp --> OVS --> eth/ip/icmp
+ 
+ AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=0,type=0)),ovs-p1"])
+ 
+-rm -rf p1.pcap
+-NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
+-sleep 1
++NETNS_DAEMONIZE([at_ns1],
++  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
++OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
+ 
+-dnl The hex dump is an mpls packet encapsulating ethernet packet. pkt=eth/mpls/eth/ip/icmp
+-dnl The packet is sent from p0(at_ns0) interface directed to
+-dnl p1(at_ns1) interface
+-NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 00 00 00 00 00 02 00 00 00 00 00 01 88 47 00 00 21 40 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])
++m4_define([MPLS_HEADER], [m4_join([,],
++  [eth_src=00:00:00:00:00:01,eth_dst=00:00:00:00:00:02,eth_type=0x8847],
++  [mpls_label=2,mpls_ttl=64,mpls_bos=1])])
++
++m4_define([ICMP_PKT], [m4_join([,],
++  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x0800],
++  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
++  [nw_proto=1,nw_ttl=64,nw_frag=no],
++  [icmp_type=8,icmp_code=0])])
+ 
+-dnl Check the expected decapsulated on the egress interface
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000:  *36b1 *ee7c *0102 *36b1 *ee7c *0103 *0800 *4500" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010:  *0054 *0344 *4000 *4001 *2161 *0a01 *0101 *0a01" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020:  *0102 *0800 *efac *7ce4 *0003 *5b2c *1f61 *0000" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030:  *0000 *500b *0200 *0000 *0000 *1011 *1213 *1415" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0040:  *1617 *1819 *1a1b *1c1d *1e1f *2021 *2223 *2425" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0050:  *2627 *2829 *2a2b *2c2d *2e2f *3031 *3233 *3435" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0060:  *3637" 2>&1 1>/dev/null])
++dnl The packet is an eth/mpls/eth/ip/icmp sent from p0(at_ns0) interface
++dnl directed to p1(at_ns1) interface.
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    "$(ovs-ofctl compose-packet --bare 'MPLS_HEADER')"  \
++    "$(ovs-ofctl compose-packet --bare 'ICMP_PKT')"],
++  [0], [ignore])
+ 
++dnl Check the expected decapsulated on the egress interface.
++OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q \
++    "^$(ovs-ofctl compose-packet --bare 'ICMP_PKT')\$"])
+ 
+ OVS_TRAFFIC_VSWITCHD_STOP
+ AT_CLEANUP
+@@ -2172,24 +2357,30 @@ dnl eth/mpls/eth/ip/icmp --> OVS --> eth/ip/icmp
+ 
+ AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=0,type=0)),ovs-p1"])
+ 
+-rm -rf p1.pcap
+-NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
+-sleep 1
++NETNS_DAEMONIZE([at_ns1],
++  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
++OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
+ 
+-dnl The hex dump is an mpls packet encapsulating ethernet packet. pkt=eth/mpls/eth/ip/icmp
+-dnl The packet is sent from p0(at_ns0) interface directed to
+-dnl p1(at_ns1) interface
+-NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 00 00 00 00 00 02 00 00 00 00 00 01 88 47 00 00 21 40 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])
++m4_define([MPLS_HEADER], [m4_join([,],
++  [eth_src=00:00:00:00:00:01,eth_dst=00:00:00:00:00:02,eth_type=0x8847],
++  [mpls_label=2,mpls_ttl=64,mpls_bos=1])])
++
++m4_define([ICMP_PKT], [m4_join([,],
++  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x0800],
++  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
++  [nw_proto=1,nw_ttl=64,nw_frag=no],
++  [icmp_type=8,icmp_code=0])])
+ 
+-dnl Check the expected decapsulated on the egress interface
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000:  *36b1 *ee7c *0102 *36b1 *ee7c *0103 *0800 *4500" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010:  *0054 *0344 *4000 *4001 *2161 *0a01 *0101 *0a01" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020:  *0102 *0800 *efac *7ce4 *0003 *5b2c *1f61 *0000" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030:  *0000 *500b *0200 *0000 *0000 *1011 *1213 *1415" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0040:  *1617 *1819 *1a1b *1c1d *1e1f *2021 *2223 *2425" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0050:  *2627 *2829 *2a2b *2c2d *2e2f *3031 *3233 *3435" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0060:  *3637" 2>&1 1>/dev/null])
++dnl The packet is an eth/mpls/eth/ip/icmp sent from p0(at_ns0) interface
++dnl directed to p1(at_ns1) interface.
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    "$(ovs-ofctl compose-packet --bare 'MPLS_HEADER')"  \
++    "$(ovs-ofctl compose-packet --bare 'ICMP_PKT')"],
++  [0], [ignore])
+ 
++dnl Check the expected decapsulated on the egress interface.
++OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q \
++    "^$(ovs-ofctl compose-packet --bare 'ICMP_PKT')\$"])
+ 
+ OVS_TRAFFIC_VSWITCHD_STOP
+ AT_CLEANUP
+@@ -2343,6 +2534,7 @@ AT_CLEANUP
  
  AT_SETUP([conntrack - ct flush])
  CHECK_CONNTRACK()
@@ -14845,7 +15324,7 @@ index 221d96aefb..7927f8e53c 100644
  OVS_TRAFFIC_VSWITCHD_START()
  
  ADD_NAMESPACES(at_ns0, at_ns1)
-@@ -2353,15 +2482,15 @@ ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
+@@ -2353,15 +2545,15 @@ ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
  AT_DATA([flows.txt], [dnl
  priority=1,action=drop
  priority=10,arp,action=normal
@@ -14865,7 +15344,7 @@ index 221d96aefb..7927f8e53c 100644
                           [ovs-ofctl ct-flush br0]], [
  AS_BOX([Testing with FLUSH_CMD])
  
-@@ -2389,7 +2518,7 @@ AT_CHECK([FLUSH_CMD zone=5 'ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=17
+@@ -2389,7 +2581,7 @@ AT_CHECK([FLUSH_CMD zone=5 'ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=17
  AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0])
  
  dnl Test ICMP traffic
@@ -14874,11 +15353,10 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -2503,9 +2632,68 @@ udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.
- 
+@@ -2504,8 +2696,67 @@ udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.
  AT_CHECK([FLUSH_CMD zone=5 '' 'ct_nw_src=10.1.1.1'])
  
-+AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [1])
+ AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [1])
 +
 +dnl Test UDP from port 1 and 2, flush without arguments
 +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
@@ -14888,8 +15366,8 @@ index 221d96aefb..7927f8e53c 100644
 +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1" | sort], [0], [dnl
 +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1)
 +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
-+])
-+
+ ])
+ 
 +AT_CHECK([FLUSH_CMD])
 +
 +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [1])
@@ -14911,9 +15389,9 @@ index 221d96aefb..7927f8e53c 100644
 +
 +AT_CHECK([FLUSH_CMD 'ct_nw_src=10.1.1.2,ct_nw_proto=132,ct_tp_src=2,ct_tp_dst=1'])
 +
- AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [1])
- ])
- 
++AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [1])
++])
++
 +dnl Test flush with invalid arguments
 +
 +AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=invalid 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1'], [2], [ignore], [stderr])
@@ -14943,7 +15421,7 @@ index 221d96aefb..7927f8e53c 100644
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
  
-@@ -2530,7 +2718,7 @@ priority=100,in_port=2,icmp,ct_state=+trk+est,action=1
+@@ -2530,7 +2781,7 @@ priority=100,in_port=2,icmp,ct_state=+trk+est,action=1
  AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
  
  dnl Pings from ns0->ns1 should work fine.
@@ -14952,7 +15430,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -2538,7 +2726,10 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
+@@ -2538,7 +2789,10 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
  icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0)
  ])
  
@@ -14964,7 +15442,7 @@ index 221d96aefb..7927f8e53c 100644
  
  dnl Pings from ns1->ns0 should fail.
  NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -w 2 10.1.1.1 | FORMAT_PING], [0], [dnl
-@@ -2571,7 +2762,7 @@ priority=100,in_port=2,icmp,ct_state=+trk+est,action=1
+@@ -2571,7 +2825,7 @@ priority=100,in_port=2,icmp,ct_state=+trk+est,action=1
  AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
  
  dnl Pings from ns0->ns1 should work fine.
@@ -14973,7 +15451,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -2671,7 +2862,7 @@ NS_CHECK_EXEC([at_ns1], [ping6 -q -c 3 -i 0.3 -w 2 fc00::1 | FORMAT_PING], [0],
+@@ -2671,7 +2925,7 @@ NS_CHECK_EXEC([at_ns1], [ping6 -q -c 3 -i 0.3 -w 2 fc00::1 | FORMAT_PING], [0],
  ])
  
  dnl Pings from ns0->ns1 should work fine.
@@ -14982,7 +15460,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -2679,6 +2870,11 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
+@@ -2679,6 +2933,11 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
  icmpv6,orig=(src=fc00::1,dst=fc00::2,id=<cleared>,type=128,code=0),reply=(src=fc00::2,dst=fc00::1,id=<cleared>,type=129,code=0)
  ])
  
@@ -14994,7 +15472,7 @@ index 221d96aefb..7927f8e53c 100644
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
  
-@@ -3579,12 +3775,12 @@ dnl Modify userspace conntrack fragmentation handling.
+@@ -3579,12 +3838,12 @@ dnl Modify userspace conntrack fragmentation handling.
  DPCTL_MODIFY_FRAGMENTATION()
  
  dnl Ipv4 fragmentation connectivity check.
@@ -15009,7 +15487,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -3656,12 +3852,12 @@ dnl Modify userspace conntrack fragmentation handling.
+@@ -3656,12 +3915,12 @@ dnl Modify userspace conntrack fragmentation handling.
  DPCTL_MODIFY_FRAGMENTATION()
  
  dnl Ipv4 fragmentation connectivity check.
@@ -15024,7 +15502,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -3701,22 +3897,22 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
+@@ -3701,22 +3960,22 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
  OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2])
  
  dnl Ipv4 fragmentation connectivity check.
@@ -15051,7 +15529,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -3875,12 +4071,12 @@ dnl "connect: Cannot assign requested address"
+@@ -3875,12 +4134,12 @@ dnl "connect: Cannot assign requested address"
  OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])
  
  dnl Ipv6 fragmentation connectivity check.
@@ -15066,7 +15544,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -3957,12 +4153,12 @@ dnl "connect: Cannot assign requested address"
+@@ -3957,12 +4216,12 @@ dnl "connect: Cannot assign requested address"
  OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])
  
  dnl Ipv4 fragmentation connectivity check.
@@ -15081,7 +15559,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -4000,22 +4196,22 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
+@@ -4000,22 +4259,22 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
  OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00:1::4])
  
  dnl Ipv6 fragmentation connectivity check.
@@ -15108,7 +15586,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -4226,18 +4422,18 @@ ADD_NATIVE_TUNNEL([vxlan], [at_vxlan1], [at_ns0], [172.31.1.100], [10.1.1.1/24],
+@@ -4226,18 +4485,18 @@ ADD_NATIVE_TUNNEL([vxlan], [at_vxlan1], [at_ns0], [172.31.1.100], [10.1.1.1/24],
                    [id 0 dstport 4789])
  
  dnl First, check the underlay
@@ -15131,7 +15609,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -4286,18 +4482,18 @@ dnl "connect: Cannot assign requested address"
+@@ -4286,18 +4545,18 @@ dnl "connect: Cannot assign requested address"
  OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])
  
  dnl First, check the underlay
@@ -15154,7 +15632,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -4410,7 +4606,7 @@ dnl The default udp_single and icmp_first timeouts are 30 seconds in
+@@ -4410,7 +4669,7 @@ dnl The default udp_single and icmp_first timeouts are 30 seconds in
  dnl kernel DP, and 60 seconds in userspace DP.
  
  dnl Send ICMP and UDP traffic
@@ -15163,7 +15641,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
-@@ -4436,7 +4632,7 @@ done
+@@ -4436,7 +4695,7 @@ done
  AT_CHECK([ovs-vsctl --may-exist add-zone-tp $DP_TYPE zone=5 udp_first=1 udp_single=1 icmp_first=1 icmp_reply=1])
  
  dnl Send ICMP and UDP traffic
@@ -15172,7 +15650,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
-@@ -4454,7 +4650,7 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
+@@ -4454,7 +4713,7 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
  ])
  
  dnl Re-send ICMP and UDP traffic to test conntrack cache
@@ -15181,7 +15659,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
-@@ -4475,7 +4671,7 @@ dnl Set the timeout policy to default again.
+@@ -4475,7 +4734,7 @@ dnl Set the timeout policy to default again.
  AT_CHECK([ovs-vsctl del-zone-tp $DP_TYPE zone=5])
  
  dnl Send ICMP and UDP traffic
@@ -15190,7 +15668,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
-@@ -4668,7 +4864,7 @@ table=2,in_port=1,ip,ct_state=+trk+est,ct_zone=2,action=LOCAL
+@@ -4668,7 +4927,7 @@ table=2,in_port=1,ip,ct_state=+trk+est,ct_zone=2,action=LOCAL
  
  AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
  
@@ -15199,7 +15677,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -4739,7 +4935,7 @@ table=4,priority=100,ip,action=output:NXM_NX_REG0[[]]
+@@ -4739,7 +4998,7 @@ table=4,priority=100,ip,action=output:NXM_NX_REG0[[]]
  
  AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
  
@@ -15208,7 +15686,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -5434,11 +5630,11 @@ ADD_NAMESPACES(at_ns0, at_ns1)
+@@ -5434,11 +5693,11 @@ ADD_NAMESPACES(at_ns0, at_ns1)
  ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
  NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
  ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
@@ -15222,7 +15700,7 @@ index 221d96aefb..7927f8e53c 100644
  in_port=2,ct_state=-trk,tcp,tp_dst=34568,action=ct(table=0,zone=1,nat)
  in_port=2,ct_state=+trk,ct_zone=1,tcp,action=1
  dnl
-@@ -5462,17 +5658,29 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
+@@ -5462,17 +5721,29 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
  
  dnl HTTP requests from p0->p1 should work fine.
  OVS_START_L7([at_ns1], [http])
@@ -15256,7 +15734,7 @@ index 221d96aefb..7927f8e53c 100644
  AT_CLEANUP
  
  AT_SETUP([conntrack - more complex SNAT])
-@@ -5763,7 +5971,7 @@ table=10 priority=0 action=drop
+@@ -5763,7 +6034,7 @@ table=10 priority=0 action=drop
  AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
  
  rm p0.pcap
@@ -15265,7 +15743,7 @@ index 221d96aefb..7927f8e53c 100644
  sleep 1
  
  dnl UDP packets from ns0->ns1 should solicit "destination unreachable" response.
-@@ -5787,7 +5995,7 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst=
+@@ -5787,7 +6058,7 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst=
  udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.2XX,sport=<cleared>,dport=<cleared>),mark=1
  ])
  
@@ -15274,7 +15752,7 @@ index 221d96aefb..7927f8e53c 100644
  
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
-@@ -6477,7 +6685,7 @@ dnl waiting, we get occasional failures due to the following error:
+@@ -6477,7 +6748,7 @@ dnl waiting, we get occasional failures due to the following error:
  dnl "connect: Cannot assign requested address"
  OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::240])
  
@@ -15283,7 +15761,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -6531,13 +6739,13 @@ OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])
+@@ -6531,13 +6802,13 @@ OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])
  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
  
  rm p0.pcap
@@ -15299,7 +15777,29 @@ index 221d96aefb..7927f8e53c 100644
  
  AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
  udp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::240,sport=<cleared>,dport=<cleared>)
-@@ -7172,12 +7380,12 @@ ADD_NATIVE_TUNNEL([geneve], [ns_gnv0], [at_ns0], [172.31.1.100], [10.1.1.1/24],
+@@ -7125,10 +7396,18 @@ table=2,priority=10  ct_state=+trk+est action=drop
+ 
+ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
+ 
+-# sending icmp pkts, first and second
+-NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f0 00 00 01 01 02 f0 00 00 01 01 01 08 00 45 00 00 1c 00 01 00 00 40 01 64 dc 0a 01 01 01 0a 01 01 02 08 00 f7 ff ff ff ff ff > /dev/null])
++m4_define([ICMP_PKT], [m4_join([,],
++  [eth_src=f0:00:00:01:01:01,eth_dst=f0:00:00:01:01:02,eth_type=0x0800],
++  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
++  [nw_proto=1,nw_ttl=64,nw_frag=no],
++  [icmp_type=8,icmp_code=0])])
++
++# Sending ICMP packets, first and second.
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    $(ovs-ofctl compose-packet --bare 'ICMP_PKT' '')], [0], [ignore])
+ 
+-NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f0 00 00 01 01 02 f0 00 00 01 01 01 08 00 45 00 00 1c 00 01 00 00 40 01 64 dc 0a 01 01 01 0a 01 01 02 08 00 f7 ff ff ff ff ff > /dev/null])
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    $(ovs-ofctl compose-packet --bare 'ICMP_PKT' '')], [0], [ignore])
+ 
+ sleep 1
+ 
+@@ -7172,12 +7451,12 @@ ADD_NATIVE_TUNNEL([geneve], [ns_gnv0], [at_ns0], [172.31.1.100], [10.1.1.1/24],
                    [vni 0])
  
  dnl First, check the underlay
@@ -15314,7 +15814,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -7220,7 +7428,7 @@ table=2,in_port=ovs-server,ip,ct_state=+trk+rpl,actions=output:ovs-client
+@@ -7220,7 +7499,7 @@ table=2,in_port=ovs-server,ip,ct_state=+trk+rpl,actions=output:ovs-client
  AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
  
  rm server.pcap
@@ -15323,7 +15823,7 @@ index 221d96aefb..7927f8e53c 100644
  OVS_WAIT_UNTIL([grep "listening" tcpdump0_err])
  
  dnl Send UDP client->server
-@@ -7262,7 +7470,7 @@ dnl Check the ICMP error in reply direction
+@@ -7262,7 +7541,7 @@ dnl Check the ICMP error in reply direction
  AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=42])
  
  rm client.pcap
@@ -15332,7 +15832,7 @@ index 221d96aefb..7927f8e53c 100644
  OVS_WAIT_UNTIL([grep "listening" tcpdump1_err])
  
  dnl Send UDP client->server
-@@ -7300,6 +7508,65 @@ AT_CHECK([ovs-pcap client.pcap | grep 000000002010000000002000], [0], [dnl
+@@ -7300,6 +7579,65 @@ AT_CHECK([ovs-pcap client.pcap | grep 000000002010000000002000], [0], [dnl
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
  
@@ -15398,7 +15898,7 @@ index 221d96aefb..7927f8e53c 100644
  AT_BANNER([IGMP])
  
  AT_SETUP([IGMP - flood under normal action])
-@@ -7404,7 +7671,7 @@ dnl CVLAN traffic should match the flow and drop
+@@ -7404,7 +7742,7 @@ dnl CVLAN traffic should match the flow and drop
  AT_CHECK([ovs-appctl revalidator/purge])
  AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:vlan-limit=1])
  AT_CHECK([ovs-ofctl add-flow br0 "priority=100 dl_type=0x8100 action=drop"])
@@ -15407,7 +15907,7 @@ index 221d96aefb..7927f8e53c 100644
  
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
-@@ -7454,11 +7721,11 @@ AT_CHECK([ovs-ofctl --bundle add-flows br2 flows-customer-br.txt])
+@@ -7454,11 +7792,11 @@ AT_CHECK([ovs-ofctl --bundle add-flows br2 flows-customer-br.txt])
  
  OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2])
  
@@ -15421,7 +15921,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -7510,11 +7777,11 @@ AT_CHECK([ovs-ofctl --bundle add-flows br2 flows-customer-br.txt])
+@@ -7510,11 +7848,11 @@ AT_CHECK([ovs-ofctl --bundle add-flows br2 flows-customer-br.txt])
  
  OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2])
  
@@ -15435,7 +15935,7 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
-@@ -7562,24 +7829,24 @@ AT_CHECK([ovs-vsctl set port ovs-p2 vlan_mode=dot1q-tunnel tag=4094 cvlans=100,2
+@@ -7562,24 +7900,24 @@ AT_CHECK([ovs-vsctl set port ovs-p2 vlan_mode=dot1q-tunnel tag=4094 cvlans=100,2
  OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2])
  OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.3.2.2])
  
@@ -15465,7 +15965,7 @@ index 221d96aefb..7927f8e53c 100644
  
  OVS_TRAFFIC_VSWITCHD_STOP(["/dropping VLAN \(0\|300\) packet received on dot1q-tunnel port/d"])
  AT_CLEANUP
-@@ -7608,11 +7875,11 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows-br0.txt])
+@@ -7608,11 +7946,11 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows-br0.txt])
  
  OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2])
  
@@ -15479,6 +15979,220 @@ index 221d96aefb..7927f8e53c 100644
  3 packets transmitted, 3 received, 0% packet loss, time 0ms
  ])
  
+@@ -7634,21 +7972,29 @@ dnl The flow will encap a nsh header to the TCP syn packet
+ dnl eth/ip/tcp --> OVS --> eth/nsh/eth/ip/tcp
+ AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,in_port=ovs-p0,ip,actions=encap(nsh(md_type=1)),set_field:0x1234->nsh_spi,set_field:0x11223344->nsh_c1,encap(ethernet),set_field:f2:ff:00:00:00:02->dl_dst,set_field:f2:ff:00:00:00:01->dl_src,ovs-p1"])
+ 
+-NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
+-sleep 1
++NETNS_DAEMONIZE([at_ns1],
++  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
++OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
+ 
+-dnl The hex dump is a TCP syn packet. pkt=eth/ip/tcp
+-dnl The packet is sent from p0(at_ns0) interface directed to
+-dnl p1(at_ns1) interface
+-NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])
++m4_define([TCP_SYN_PKT], [m4_join([,],
++  [eth_src=f2:00:00:00:00:01,eth_dst=f2:00:00:00:00:02,eth_type=0x0800],
++  [nw_src=192.168.0.10,nw_dst=10.0.0.10],
++  [nw_proto=6,nw_ttl=64,nw_frag=no],
++  [tcp_src=1024,tcp_dst=2048,tcp_flags=syn])])
++
++dnl Send the TCP SYN packet from p0(at_ns0) interface directed to
++dnl p1(at_ns1) interface.
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    $(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')], [0], [ignore])
++
++m4_define([NSH_HEADER], [m4_join([,],
++  [eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
++  [nsh_ttl=63,nsh_np=3,nsh_spi=0x1234,nsh_si=255],
++  [nsh_mdtype=1,nsh_c1=0x11223344])])
+ 
+-dnl Check the expected nsh encapsulated packet on the egress interface
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000: *f2ff *0000 *0002 *f2ff *0000 *0001 *894f *0fc6" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010: *0103 *0012 *34ff *1122 *3344 *0000 *0000 *0000" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020: *0000 *0000 *0000 *f200 *0000 *0002 *f200 *0000" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030: *0001 *0800 *4500 *0028 *0001 *0000 *4006 *b013" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0040: *c0a8 *000a *0a00 *000a *0400 *0800 *0000 *00c8" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0050: *0000 *0000 *5002 *2000 *b85e *0000" 2>&1 1>/dev/null])
++OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
++    $(ovs-ofctl compose-packet --bare 'NSH_HEADER'),
++    $(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT'), [\$])"])
+ 
+ OVS_TRAFFIC_VSWITCHD_STOP
+ AT_CLEANUP
+@@ -7666,19 +8012,31 @@ dnl The flow will decap a nsh header which in turn carries a TCP syn packet
+ dnl eth/nsh/eth/ip/tcp --> OVS --> eth/ip/tcp
+ AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,in_port=ovs-p0,dl_type=0x894f, actions=decap(),decap(), ovs-p1"])
+ 
+-NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
+-sleep 1
++NETNS_DAEMONIZE([at_ns1],
++  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
++OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
+ 
+-dnl The hex dump is NSH packet with TCP syn payload. pkt=eth/nsh/eth/ip/tcp
+-dnl The packet is sent from p0(at_ns0) interface directed to
+-dnl p1(at_ns1) interface
+-NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 ff 00 00 00 02 f2 ff 00 00 00 01 89 4f 02 06 01 03 00 00 64 03 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])
++m4_define([TCP_SYN_PKT], [m4_join([,],
++  [eth_src=f2:00:00:00:00:01,eth_dst=f2:00:00:00:00:02,eth_type=0x0800],
++  [nw_src=192.168.0.10,nw_dst=10.0.0.10],
++  [nw_proto=6,nw_ttl=64,nw_frag=no],
++  [tcp_src=1024,tcp_dst=2048,tcp_flags=syn])])
++
++m4_define([NSH_HEADER], [m4_join([,],
++  [eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
++  [nsh_ttl=63,nsh_np=3,nsh_spi=0x1234,nsh_si=255],
++  [nsh_mdtype=1,nsh_c1=0x11223344])])
++
++dnl Send the NSH packet with TCP SYN payload from p0(at_ns0) interface directed
++dnl to p1(at_ns1) interface.
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    "$(ovs-ofctl compose-packet --bare 'NSH_HEADER')" \
++    "$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')"],
++  [0], [ignore])
+ 
+ dnl Check the expected de-capsulated TCP packet on the egress interface
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000: *f200 *0000 *0002 *f200 *0000 *0001 *0800 *4500" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010: *0028 *0001 *0000 *4006 *b013 *c0a8 *000a *0a00" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020: *000a *0400 *0800 *0000 *00c8 *0000 *0000 *5002" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030: *2000 *b85e *0000" 2>&1 1>/dev/null])
++OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q \
++    "^$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')\$"])
+ 
+ OVS_TRAFFIC_VSWITCHD_STOP
+ AT_CLEANUP
+@@ -7698,22 +8056,38 @@ dnl The flow will add another NSH header with nsh_spi=0x101, nsh_si=4,
+ dnl nsh_ttl=7 and change the md1 context
+ AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,in_port=ovs-p0,dl_type=0x894f,nsh_spi=0x100,nsh_si=0x03,actions=decap(),decap(),encap(nsh(md_type=1)),set_field:0x07->nsh_ttl,set_field:0x0101->nsh_spi,set_field:0x04->nsh_si,set_field:0x100f0e0d->nsh_c1,set_field:0x0c0b0a09->nsh_c2,set_field:0x08070605->nsh_c3,set_field:0x04030201->nsh_c4,encap(ethernet),set_field:f2:ff:00:00:00:02->dl_dst,set_field:f2:ff:00:00:00:01->dl_src,ovs-p1"])
+ 
+-NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
+-sleep 1
++NETNS_DAEMONIZE([at_ns1],
++  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
++OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
+ 
+-dnl The hex dump is NSH packet with TCP syn payload. pkt=eth/nsh/eth/ip/tcp
+-dnl The nsh_ttl is 8, nsh_spi is 0x100 and nsh_si is 3
+-dnl The packet is sent from p0(at_ns0) interface directed to
+-dnl p1(at_ns1) interface
+-NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 ff 00 00 00 02 f2 ff 00 00 00 01 89 4f 02 06 01 03 00 01 00 03 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])
++m4_define([TCP_SYN_PKT], [m4_join([,],
++  [eth_src=f2:00:00:00:00:01,eth_dst=f2:00:00:00:00:02,eth_type=0x0800],
++  [nw_src=192.168.0.10,nw_dst=10.0.0.10],
++  [nw_proto=6,nw_ttl=64,nw_frag=no],
++  [tcp_src=1024,tcp_dst=2048,tcp_flags=syn])])
+ 
+-dnl Check the expected NSH packet with new fields in the header
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000: *f2ff *0000 *0002 *f2ff *0000* 0001 *894f *01c6" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010: *0103 *0001 *0104 *100f *0e0d *0c0b *0a09 *0807" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020: *0605 *0403 *0201 *f200 *0000 *0002 *f200 *0000" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030: *0001 *0800 *4500 *0028 *0001 *0000 *4006 *b013" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0040: *c0a8 *000a *0a00 *000a *0400 *0800 *0000 *00c8" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0050: *0000 *0000 *5002 *2000 *b85e *0000" 2>&1 1>/dev/null])
++m4_define([NSH_HEADER_1], [m4_join([,],
++  [eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
++  [nsh_ttl=8,nsh_np=3,nsh_spi=0x100,nsh_si=3,nsh_mdtype=1],
++  [nsh_c1=0x01020304,nsh_c2=0x05060708,nsh_c3=0x090a0b0c,nsh_c4=0x0d0e0f10])])
++
++dnl Send the NSH packet with TCP SYN payload from p0(at_ns0) interface directed
++dnl to p1(at_ns1) interface.
++dnl The nsh_ttl is 8, nsh_spi is 0x100 and nsh_si is 3.
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    "$(ovs-ofctl compose-packet --bare 'NSH_HEADER_1')" \
++    "$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')"],
++  [0], [ignore])
++
++m4_define([NSH_HEADER_2], [m4_join([,],
++  [eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
++  [nsh_ttl=7,nsh_np=3,nsh_spi=0x101,nsh_si=4,nsh_mdtype=1],
++  [nsh_c1=0x100f0e0d,nsh_c2=0x0c0b0a09,nsh_c3=0x08070605,nsh_c4=0x04030201])])
++
++dnl Check the expected NSH packet with new fields in the header.
++OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
++    $(ovs-ofctl compose-packet --bare 'NSH_HEADER_2'),
++    $(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT'), [\$])"])
+ 
+ OVS_TRAFFIC_VSWITCHD_STOP
+ AT_CLEANUP
+@@ -7734,31 +8108,50 @@ dnl packet to to at_ns2.
+ AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x894f,nsh_spi=0x100,nsh_si=0x02,actions=ovs-p1"])
+ AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x894f,nsh_spi=0x100,nsh_si=0x01,actions=ovs-p2"])
+ 
+-NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
+-NETNS_DAEMONIZE([at_ns2], [tcpdump -l -n -xx -U -i p2 > p2.pcap], [tcpdump2.pid])
+-sleep 1
+-
+-dnl First send packet from at_ns0 --> OVS with SPI=0x100 and SI=2
+-NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 ff 00 00 00 02 f2 ff 00 00 00 01 89 4f 02 06 01 03 00 01 00 02 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])
+-
+-dnl Check for the above packet on p1 interface
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000: *f2ff *0000 *0002 *f2ff *0000 *0001 *894f *0206" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010: *0103 *0001 *0002 *0102 *0304 *0506 *0708 *090a" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020: *0b0c *0d0e *0f10 *f200 *0000 *0002 *f200 *0000" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030: *0001 *0800 *4500 *0028 *0001 *0000 *4006 *b013" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0040: *c0a8 *000a *0a00 *000a *0400 *0800 *0000 *00c8" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0050: *0000 *0000 *5002 *2000 *b85e *0000" 2>&1 1>/dev/null])
+-
+-dnl Send the second packet from at_ns1 --> OVS with SPI=0x100 and SI=1
+-NS_CHECK_EXEC([at_ns1], [$PYTHON3 $srcdir/sendpkt.py p1 f2 ff 00 00 00 02 f2 ff 00 00 00 01 89 4f 01 c6 01 03 00 01 00 01 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])
+-
+-dnl Check for the above packet on p2 interface
+-OVS_WAIT_UNTIL([cat p2.pcap | grep -E "0x0000: *f2ff *0000 *0002 *f2ff *0000 *0001 *894f *01c6" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p2.pcap | grep -E "0x0010: *0103 *0001 *0001 *0102 *0304 *0506 *0708 *090a" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p2.pcap | grep -E "0x0020: *0b0c *0d0e *0f10 *f200 *0000 *0002 *f200 *0000" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p2.pcap | grep -E "0x0030: *0001 *0800 *4500 *0028 *0001 *0000 *4006 *b013" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p2.pcap | grep -E "0x0040: *c0a8 *000a *0a00 *000a *0400 *0800 *0000 *00c8" 2>&1 1>/dev/null])
+-OVS_WAIT_UNTIL([cat p2.pcap | grep -E "0x0050: *0000 *0000 *5002 *2000 *b85e *0000" 2>&1 1>/dev/null])
++NETNS_DAEMONIZE([at_ns1],
++  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
++OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
++NETNS_DAEMONIZE([at_ns2],
++  [tcpdump -l -n -xx -U -i p2 -w p2.pcap 2>tcpdump2_err], [tcpdump2.pid])
++OVS_WAIT_UNTIL([grep "listening" tcpdump2_err])
++
++m4_define([TCP_SYN_PKT], [m4_join([,],
++  [eth_src=f2:00:00:00:00:01,eth_dst=f2:00:00:00:00:02,eth_type=0x0800],
++  [nw_src=192.168.0.10,nw_dst=10.0.0.10],
++  [nw_proto=6,nw_ttl=64,nw_frag=no],
++  [tcp_src=1024,tcp_dst=2048,tcp_flags=syn])])
++
++dnl First send packet from at_ns0 --> OVS with SPI=0x100 and SI=2.
++m4_define([NSH_HEADER_1], [m4_join([,],
++  [eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
++  [nsh_ttl=8,nsh_np=3,nsh_spi=0x100,nsh_si=2,nsh_mdtype=1],
++  [nsh_c1=0x01020304,nsh_c2=0x05060708,nsh_c3=0x090a0b0c,nsh_c4=0x0d0e0f10])])
++
++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
++    "$(ovs-ofctl compose-packet --bare 'NSH_HEADER_1')" \
++    "$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')"],
++  [0], [ignore])
++
++dnl Check for the above packet on p1 interface.
++OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
++    $(ovs-ofctl compose-packet --bare 'NSH_HEADER_1'),
++    $(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT'), [\$])"])
++
++dnl Send the second packet from at_ns1 --> OVS with SPI=0x100 and SI=1.
++m4_define([NSH_HEADER_2], [m4_join([,],
++  [eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
++  [nsh_ttl=8,nsh_np=3,nsh_spi=0x100,nsh_si=1,nsh_mdtype=1],
++  [nsh_c1=0x01020304,nsh_c2=0x05060708,nsh_c3=0x090a0b0c,nsh_c4=0x0d0e0f10])])
++
++NS_CHECK_EXEC([at_ns1], [$PYTHON3 $srcdir/sendpkt.py p1 \
++    "$(ovs-ofctl compose-packet --bare 'NSH_HEADER_2')" \
++    "$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')"],
++  [0], [ignore])
++
++dnl Check for the above packet on p2 interface.
++OVS_WAIT_UNTIL([ovs-pcap p2.pcap | grep -q "m4_join([], [^],
++    $(ovs-ofctl compose-packet --bare 'NSH_HEADER_2'),
++    $(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT'), [\$])"])
+ 
+ OVS_TRAFFIC_VSWITCHD_STOP
+ AT_CLEANUP
 diff --git a/tests/system-userspace-macros.at b/tests/system-userspace-macros.at
 index b34a84775b..2db62bf8d9 100644
 --- a/tests/system-userspace-macros.at
diff --git a/SPECS/openvswitch3.1.spec b/SPECS/openvswitch3.1.spec
index 3c3e203..eccf1df 100644
--- a/SPECS/openvswitch3.1.spec
+++ b/SPECS/openvswitch3.1.spec
@@ -57,7 +57,7 @@ Summary: Open vSwitch
 Group: System Environment/Daemons daemon/database/utilities
 URL: http://www.openvswitch.org/
 Version: 3.1.0
-Release: 115%{?dist}
+Release: 116%{?dist}
 
 # Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
 # lib/sflow*.[ch] files are SISSL
@@ -754,6 +754,16 @@ exit 0
 %endif
 
 %changelog
+* Wed Jun 05 2024 Open vSwitch CI <ovs-ci@redhat.com> - 3.1.0-116
+- Merging upstream branch-3.1 [RH git: bc729227ad]
+    Commit list:
+    5a9788b674 nsh: Add support to compose-packet and use it in system tests.
+    33ad96d911 tests: Convert ND, MPLS and CT sendpkt tests to compose-packet.
+    282e1ce82b tests: sendpkt: Allow different input formats.
+    9e178b6752 ipf: Handle common case of ipf defragmentation.
+    f0f186095b ipf: Only add fragments to batch of same dl_type.
+
+
 * Mon Jun 03 2024 Open vSwitch CI <ovs-ci@redhat.com> - 3.1.0-115
 - Merging upstream branch-3.1 [RH git: a33dc9cef4]
     Commit list: