diff --git a/controller/mac-learn.c b/controller/mac-learn.c
index 071f01b4f..0c3b60c23 100644
--- a/controller/mac-learn.c
+++ b/controller/mac-learn.c
@@ -199,15 +199,24 @@ ovn_fdb_add(struct hmap *fdbs, uint32_t dp_key, struct eth_addr mac,
 /* packet buffering functions */
 
 struct packet_data *
-ovn_packet_data_create(struct ofpbuf ofpacts,
-                       const struct dp_packet *original_packet)
+ovn_packet_data_create(const struct ofputil_packet_in *pin,
+                       const struct ofpbuf *continuation)
 {
     struct packet_data *pd = xmalloc(sizeof *pd);
 
-    pd->ofpacts = ofpacts;
-    /* clone the packet to send it later with correct L2 address */
-    pd->p = dp_packet_clone_data(dp_packet_data(original_packet),
-                                 dp_packet_size(original_packet));
+    pd->pin = (struct ofputil_packet_in) {
+        .packet = xmemdup(pin->packet, pin->packet_len),
+        .packet_len = pin->packet_len,
+        .flow_metadata = pin->flow_metadata,
+        .reason = pin->reason,
+        .table_id = pin->table_id,
+        .cookie = pin->cookie,
+        /* Userdata are empty on purpose,
+         * it is not needed for the continuation. */
+        .userdata = NULL,
+        .userdata_len = 0,
+    };
+    pd->continuation = ofpbuf_clone(continuation);
 
     return pd;
 }
@@ -216,8 +225,8 @@ ovn_packet_data_create(struct ofpbuf ofpacts,
 void
 ovn_packet_data_destroy(struct packet_data *pd)
 {
-    dp_packet_delete(pd->p);
-    ofpbuf_uninit(&pd->ofpacts);
+    free(pd->pin.packet);
+    ofpbuf_delete(pd->continuation);
     free(pd);
 }
 
@@ -307,7 +316,10 @@ ovn_buffered_packets_ctx_run(struct buffered_packets_ctx *ctx,
 
         struct packet_data *pd;
         LIST_FOR_EACH_POP (pd, node, &bp->queue) {
-            struct eth_header *eth = dp_packet_data(pd->p);
+            struct dp_packet packet;
+            dp_packet_use_const(&packet, pd->pin.packet, pd->pin.packet_len);
+
+            struct eth_header *eth = dp_packet_data(&packet);
             eth->eth_dst = mac;
 
             ovs_list_push_back(&ctx->ready_packets_data, &pd->node);
diff --git a/controller/mac-learn.h b/controller/mac-learn.h
index e0fd6a8d1..20a015e1a 100644
--- a/controller/mac-learn.h
+++ b/controller/mac-learn.h
@@ -24,6 +24,7 @@
 #include "openvswitch/hmap.h"
 #include "openvswitch/list.h"
 #include "openvswitch/ofpbuf.h"
+#include "openvswitch/ofp-packet.h"
 
 struct ovsdb_idl_index;
 
@@ -91,8 +92,8 @@ struct fdb_entry *ovn_fdb_add(struct hmap *fdbs,
 struct packet_data {
     struct ovs_list node;
 
-    struct ofpbuf ofpacts;
-    struct dp_packet *p;
+    struct ofpbuf *continuation;
+    struct ofputil_packet_in pin;
 };
 
 struct buffered_packets {
@@ -120,8 +121,8 @@ struct buffered_packets_ctx {
 };
 
 struct packet_data *
-ovn_packet_data_create(struct ofpbuf ofpacts,
-                       const struct dp_packet *original_packet);
+ovn_packet_data_create(const struct ofputil_packet_in *pin,
+                       const struct ofpbuf *continuation);
 void ovn_packet_data_destroy(struct packet_data *pd);
 struct buffered_packets *
 ovn_buffered_packets_add(struct buffered_packets_ctx *ctx, uint64_t dp_key,
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index 9a4deb80a..2c0ecdb4c 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -258,9 +258,9 @@ static void pinctrl_handle_put_nd_ra_opts(
     struct ofpbuf *continuation);
 static void pinctrl_handle_nd_ns(struct rconn *swconn,
                                  const struct flow *ip_flow,
-                                 struct dp_packet *pkt_in,
-                                 const struct match *md,
-                                 struct ofpbuf *userdata);
+                                 const struct ofputil_packet_in *pin,
+                                 struct ofpbuf *userdata,
+                                 const struct ofpbuf *continuation);
 static void pinctrl_handle_put_icmp_frag_mtu(struct rconn *swconn,
                                              const struct flow *in_flow,
                                              struct dp_packet *pkt_in,
@@ -1534,11 +1534,13 @@ destroy_buffered_packets_ctx(void)
 
 /* Called with in the pinctrl_handler thread context. */
 static void
-pinctrl_handle_buffered_packets(struct dp_packet *pkt_in,
-                                const struct match *md, bool is_arp)
+pinctrl_handle_buffered_packets(const struct ofputil_packet_in *pin,
+                                const struct ofpbuf *continuation,
+                                bool is_arp)
 OVS_REQUIRES(pinctrl_mutex)
 {
     struct in6_addr ip;
+    const struct match *md = &pin->flow_metadata;
     uint64_t dp_key = ntohll(md->flow.metadata);
     uint64_t oport_key = md->flow.regs[MFF_LOG_OUTPORT - MFF_REG0];
 
@@ -1556,20 +1558,7 @@ OVS_REQUIRES(pinctrl_mutex)
         return;
     }
 
-    struct ofpbuf ofpacts;
-    ofpbuf_init(&ofpacts, 4096);
-    reload_metadata(&ofpacts, md);
-    /* reload pkt_mark field */
-    const struct mf_field *pkt_mark_field = mf_from_id(MFF_PKT_MARK);
-    union mf_value pkt_mark_value;
-    mf_get_value(pkt_mark_field, &md->flow, &pkt_mark_value);
-    ofpact_put_set_field(&ofpacts, pkt_mark_field, &pkt_mark_value, NULL);
-
-    struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
-    resubmit->in_port = OFPP_CONTROLLER;
-    resubmit->table_id = OFTABLE_OUTPUT_INIT;
-
-    struct packet_data *pd = ovn_packet_data_create(ofpacts, pkt_in);
+    struct packet_data *pd = ovn_packet_data_create(pin, continuation);
     ovn_buffered_packets_packet_data_enqueue(bp, pd);
 
     /* There is a chance that the MAC binding was already created. */
@@ -1579,8 +1568,8 @@ OVS_REQUIRES(pinctrl_mutex)
 /* Called with in the pinctrl_handler thread context. */
 static void
 pinctrl_handle_arp(struct rconn *swconn, const struct flow *ip_flow,
-                   struct dp_packet *pkt_in,
-                   const struct match *md, struct ofpbuf *userdata)
+                   const struct ofputil_packet_in *pin,
+                   struct ofpbuf *userdata, const struct ofpbuf *continuation)
 {
     /* This action only works for IP packets, and the switch should only send
      * us IP packets this way, but check here just to be sure. */
@@ -1592,7 +1581,7 @@ pinctrl_handle_arp(struct rconn *swconn, const struct flow *ip_flow,
     }
 
     ovs_mutex_lock(&pinctrl_mutex);
-    pinctrl_handle_buffered_packets(pkt_in, md, true);
+    pinctrl_handle_buffered_packets(pin, continuation, true);
     ovs_mutex_unlock(&pinctrl_mutex);
 
     /* Compose an ARP packet. */
@@ -1617,7 +1606,8 @@ pinctrl_handle_arp(struct rconn *swconn, const struct flow *ip_flow,
                       ip_flow->vlans[0].tci);
     }
 
-    set_actions_and_enqueue_msg(swconn, &packet, md, userdata);
+    set_actions_and_enqueue_msg(swconn, &packet,
+                                &pin->flow_metadata, userdata);
     dp_packet_uninit(&packet);
 }
 
@@ -3294,8 +3284,7 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
 
     switch (ntohl(ah->opcode)) {
     case ACTION_OPCODE_ARP:
-        pinctrl_handle_arp(swconn, &headers, &packet, &pin.flow_metadata,
-                           &userdata);
+        pinctrl_handle_arp(swconn, &headers, &pin, &userdata, &continuation);
         break;
     case ACTION_OPCODE_IGMP:
         pinctrl_ip_mcast_handle(swconn, &headers, &packet, &pin.flow_metadata,
@@ -3361,8 +3350,7 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
         break;
 
     case ACTION_OPCODE_ND_NS:
-        pinctrl_handle_nd_ns(swconn, &headers, &packet, &pin.flow_metadata,
-                             &userdata);
+        pinctrl_handle_nd_ns(swconn, &headers, &pin, &userdata, &continuation);
         break;
 
     case ACTION_OPCODE_ICMP:
@@ -4374,16 +4362,8 @@ send_mac_binding_buffered_pkts(struct rconn *swconn)
 
     struct packet_data *pd;
     LIST_FOR_EACH_POP (pd, node, &buffered_packets_ctx.ready_packets_data) {
-        struct ofputil_packet_out po = {
-            .packet = dp_packet_data(pd->p),
-            .packet_len = dp_packet_size(pd->p),
-            .buffer_id = UINT32_MAX,
-            .ofpacts = pd->ofpacts.data,
-            .ofpacts_len = pd->ofpacts.size,
-        };
-        match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER);
-        queue_msg(swconn, ofputil_encode_packet_out(&po, proto));
-
+        queue_msg(swconn, ofputil_encode_resume(&pd->pin, pd->continuation,
+                                                proto));
         ovn_packet_data_destroy(pd);
     }
 
@@ -6317,8 +6297,9 @@ pinctrl_handle_nd_na(struct rconn *swconn, const struct flow *ip_flow,
 /* Called with in the pinctrl_handler thread context. */
 static void
 pinctrl_handle_nd_ns(struct rconn *swconn, const struct flow *ip_flow,
-                     struct dp_packet *pkt_in,
-                     const struct match *md, struct ofpbuf *userdata)
+                     const struct ofputil_packet_in *pin,
+                     struct ofpbuf *userdata,
+                     const struct ofpbuf *continuation)
 {
     /* This action only works for IPv6 packets. */
     if (get_dl_type(ip_flow) != htons(ETH_TYPE_IPV6)) {
@@ -6328,7 +6309,7 @@ pinctrl_handle_nd_ns(struct rconn *swconn, const struct flow *ip_flow,
     }
 
     ovs_mutex_lock(&pinctrl_mutex);
-    pinctrl_handle_buffered_packets(pkt_in, md, false);
+    pinctrl_handle_buffered_packets(pin, continuation, false);
     ovs_mutex_unlock(&pinctrl_mutex);
 
     uint64_t packet_stub[128 / 8];
@@ -6341,7 +6322,8 @@ pinctrl_handle_nd_ns(struct rconn *swconn, const struct flow *ip_flow,
                   &ip_flow->ipv6_dst);
 
     /* Reload previous packet metadata and set actions from userdata. */
-    set_actions_and_enqueue_msg(swconn, &packet, md, userdata);
+    set_actions_and_enqueue_msg(swconn, &packet,
+                                &pin->flow_metadata, userdata);
     dp_packet_uninit(&packet);
 }
 
diff --git a/lib/actions.c b/lib/actions.c
index 71615fc53..004b77a89 100644
--- a/lib/actions.c
+++ b/lib/actions.c
@@ -1977,6 +1977,44 @@ format_REJECT(const struct ovnact_nest *nest, struct ds *s)
     format_nested_action(nest, "reject", s);
 }
 
+static bool
+is_paused_nested_action(enum action_opcode opcode)
+{
+    switch (opcode) {
+    case ACTION_OPCODE_ARP:
+    case ACTION_OPCODE_ND_NS:
+        return true;
+    case ACTION_OPCODE_IGMP:
+    case ACTION_OPCODE_PUT_ARP:
+    case ACTION_OPCODE_PUT_DHCP_OPTS:
+    case ACTION_OPCODE_ND_NA:
+    case ACTION_OPCODE_ND_NA_ROUTER:
+    case ACTION_OPCODE_PUT_ND:
+    case ACTION_OPCODE_PUT_FDB:
+    case ACTION_OPCODE_PUT_DHCPV6_OPTS:
+    case ACTION_OPCODE_DNS_LOOKUP:
+    case ACTION_OPCODE_LOG:
+    case ACTION_OPCODE_PUT_ND_RA_OPTS:
+    case ACTION_OPCODE_ICMP:
+    case ACTION_OPCODE_ICMP4_ERROR:
+    case ACTION_OPCODE_ICMP6_ERROR:
+    case ACTION_OPCODE_TCP_RESET:
+    case ACTION_OPCODE_SCTP_ABORT:
+    case ACTION_OPCODE_REJECT:
+    case ACTION_OPCODE_PUT_ICMP4_FRAG_MTU:
+    case ACTION_OPCODE_PUT_ICMP6_FRAG_MTU:
+    case ACTION_OPCODE_EVENT:
+    case ACTION_OPCODE_BIND_VPORT:
+    case ACTION_OPCODE_DHCP6_SERVER:
+    case ACTION_OPCODE_HANDLE_SVC_CHECK:
+    case ACTION_OPCODE_BFD_MSG:
+    case ACTION_OPCODE_ACTIVATION_STRATEGY_RARP:
+    case ACTION_OPCODE_MG_SPLIT_BUF:
+    default:
+        return false;
+    }
+}
+
 static void
 encode_nested_actions(const struct ovnact_nest *on,
                       const struct ovnact_encode_params *ep,
@@ -1992,7 +2030,8 @@ encode_nested_actions(const struct ovnact_nest *on,
      * converted to OpenFlow, as its userdata.  ovn-controller will convert the
      * packet to ARP or NA and then send the packet and actions back to the
      * switch inside an OFPT_PACKET_OUT message. */
-    size_t oc_offset = encode_start_controller_op(opcode, false,
+    bool pause = is_paused_nested_action(opcode);
+    size_t oc_offset = encode_start_controller_op(opcode, pause,
                                                   ep->ctrl_meter_id, ofpacts);
     ofpacts_put_openflow_actions(inner_ofpacts.data, inner_ofpacts.size,
                                  ofpacts, OFP15_VERSION);
diff --git a/northd/northd.c b/northd/northd.c
index c568f6360..f65f0d1d9 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -13427,7 +13427,7 @@ build_arp_request_flows_for_lrouter(
                       "ip6.dst = %s; "
                       "nd.target = %s; "
                       "output; "
-                      "};", ETH_ADDR_ARGS(eth_dst), sn_addr_s,
+                      "}; output;", ETH_ADDR_ARGS(eth_dst), sn_addr_s,
                       route->nexthop);
 
         ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200,
@@ -13447,7 +13447,7 @@ build_arp_request_flows_for_lrouter(
                       "arp.tpa = " REG_NEXT_HOP_IPV4 "; "
                       "arp.op = 1; " /* ARP request */
                       "output; "
-                      "};",
+                      "}; output;",
                       copp_meter_get(COPP_ARP_RESOLVE, od->nbr->copp,
                                      meter_groups),
                       lflow_ref);
@@ -13456,7 +13456,7 @@ build_arp_request_flows_for_lrouter(
                       "nd_ns { "
                       "nd.target = " REG_NEXT_HOP_IPV6 "; "
                       "output; "
-                      "};",
+                      "}; output;",
                       copp_meter_get(COPP_ND_NS_RESOLVE, od->nbr->copp,
                                      meter_groups),
                       lflow_ref);
diff --git a/ovs b/ovs
index fe55ce37a..43db93787 160000
--- a/ovs
+++ b/ovs
@@ -1 +1 @@
-Subproject commit fe55ce37a7b090d09dee5c01ae0797320ad678f6
+Subproject commit 43db937876fcec57947634d6e642429673d1ec06
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index cd53755b2..b3f8bd158 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -6947,6 +6947,9 @@ ct_dnat /* assuming no un-dnat entry, so no change */ {
             arp.op = 1;
             output("rtr-ls");
         };
+        ct_dnat /* assuming no un-dnat entry, so no change */ {
+            output("rtr-ls");
+        };
     };
 };
 ])
diff --git a/tests/ovn.at b/tests/ovn.at
index dd2ebce98..471cafcf9 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -1540,11 +1540,11 @@ clone { ip4.dst = 255.255.255.255; output; }; next;
 
 # arp
 arp { eth.dst = ff:ff:ff:ff:ff:ff; output; }; output;
-    encodes as controller(userdata=00.00.00.00.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.OFTABLE_SAVE_INPORT_HEX.00.00.00),resubmit(,OFTABLE_SAVE_INPORT)
+    encodes as controller(userdata=00.00.00.00.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.OFTABLE_SAVE_INPORT_HEX.00.00.00,pause),resubmit(,OFTABLE_SAVE_INPORT)
     has prereqs ip4
 arp { };
     formats as arp { drop; };
-    encodes as controller(userdata=00.00.00.00.00.00.00.00)
+    encodes as controller(userdata=00.00.00.00.00.00.00.00,pause)
     has prereqs ip4
 
 # get_arp
@@ -1674,12 +1674,12 @@ reg1[[0]] = put_dhcp_opts(offerip=1.2.3.4, domain_search_list=1.2.3.4);
 
 # nd_ns
 nd_ns { nd.target = xxreg0; output; };
-    encodes as controller(userdata=00.00.00.09.00.00.00.00.00.1c.00.18.00.80.00.00.00.00.00.00.00.01.de.10.80.00.3e.10.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.OFTABLE_SAVE_INPORT_HEX.00.00.00)
+    encodes as controller(userdata=00.00.00.09.00.00.00.00.00.1c.00.18.00.80.00.00.00.00.00.00.00.01.de.10.80.00.3e.10.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.OFTABLE_SAVE_INPORT_HEX.00.00.00,pause)
     has prereqs ip6
 
 nd_ns { };
     formats as nd_ns { drop; };
-    encodes as controller(userdata=00.00.00.09.00.00.00.00)
+    encodes as controller(userdata=00.00.00.09.00.00.00.00,pause)
     has prereqs ip6
 
 # nd_na
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index fc69facb9..c69e649a6 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -12298,3 +12298,98 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
 /connection dropped.*/d"])
 AT_CLEANUP
 ])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([LB with first packet buffered])
+AT_KEYWORDS([ovnlb])
+
+CHECK_CONNTRACK()
+CHECK_CONNTRACK_NAT()
+
+ovn_start
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_BR([br-int])
+ADD_BR([br-ext])
+
+check ovs-ofctl add-flow br-ext action=normal
+# Set external-ids in br-int needed for ovn-controller
+check ovs-vsctl \
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
+        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true \
+        -- set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext
+
+# Start ovn-controller
+start_daemon ovn-controller
+
+check ovn-nbctl lr-add lr
+check ovn-nbctl ls-add internal
+check ovn-nbctl ls-add public
+
+check ovn-nbctl lrp-add lr lr-pub 00:00:01:01:02:03 192.168.100.1/24 1000::1/64
+check ovn-nbctl lsp-add  public pub-lr -- set Logical_Switch_Port pub-lr \
+    type=router options:router-port=lr-pub addresses=\"00:00:01:01:02:03\"
+
+check ovn-nbctl lrp-add lr lr-internal 00:00:01:01:02:04 192.168.200.1/24 2000::1/64
+check ovn-nbctl lsp-add internal internal-lr -- set Logical_Switch_Port internal-lr \
+    type=router options:router-port=lr-internal addresses=\"00:00:01:01:02:04\"
+
+check ovn-nbctl lsp-add internal server -- lsp-set-addresses server "unknown"
+
+ovn-nbctl lsp-add public ln_port \
+                -- lsp-set-addresses ln_port unknown \
+                -- lsp-set-type ln_port localnet \
+                -- lsp-set-options ln_port network_name=phynet
+
+check ovn-nbctl set logical_router lr options:chassis=hv1
+
+check ovn-nbctl lb-add lb1 192.168.100.20 192.168.200.10
+check ovn-nbctl lb-add lb2 1000::20 2000::10
+check ovn-nbctl lr-lb-add lr lb1
+check ovn-nbctl lr-lb-add lr lb2
+check ovn-nbctl --wait=hv sync
+
+ADD_NAMESPACES(client)
+ADD_VETH(client, client, br-ext, "1000::10/64", "f0:00:00:01:02:03", \
+         "1000::1", "nodad", "192.168.100.10/24", "192.168.100.1")
+
+ADD_NAMESPACES(server)
+ADD_VETH(server, server, br-int, "2000::10/64", "f0:00:0f:01:02:03", \
+         "2000::1", "nodad", "192.168.200.10/24", "192.168.200.1")
+
+NETNS_DAEMONIZE([server], [nc -l -u 192.168.200.10 4242 > /dev/null], [serverv4.pid])
+NETNS_DAEMONIZE([server], [nc -l -u 2000::10 4243 > /dev/null], [serverv6.pid])
+
+NETNS_START_TCPDUMP([client], [-l -U -i client -vnne udp], [client])
+NETNS_START_TCPDUMP([server], [-l -U -i server -vnne udp], [server])
+
+check ovs-appctl dpctl/flush-conntrack
+
+NS_CHECK_EXEC([client], [nc -z -u 192.168.100.20 4242], [ignore], [ignore], [ignore])
+OVS_WAIT_UNTIL([grep -q "192.168.200.10" server.tcpdump])
+
+NS_CHECK_EXEC([client], [nc -z -u 1000::20 4243])
+OVS_WAIT_UNTIL([grep -q "2000::10" server.tcpdump])
+
+zone_id=$(ovn-appctl -t ovn-controller ct-zone-list | grep lr_dnat | cut -d ' ' -f2)
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep -c "zone=$zone_id"], [0], [2
+])
+
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
+
+as ovn-sb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as ovn-nb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as northd
+OVS_APP_EXIT_AND_WAIT([ovn-northd])
+
+as
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
+/connection dropped.*/d"])
+AT_CLEANUP
+])
