diff mbox series

[ovs-dev,v3,09/16] northd: Use lflow_ref when adding all logical flows.

Message ID 20231128023644.569861-1-numans@ovn.org
State Changes Requested
Headers show
Series northd lflow incremental processing | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test fail github build: failed
ovsrobot/github-robot-_ovn-kubernetes success github build: passed
ovsrobot/github-robot-_Build_and_Test fail github build: failed
ovsrobot/github-robot-_ovn-kubernetes success github build: passed

Commit Message

Numan Siddique Nov. 28, 2023, 2:36 a.m. UTC
From: Numan Siddique <numans@ovn.org>

ovn_lflow_add* macros now expect 'lflow_ref' to be passed
and it can be NULL too.

Signed-off-by: Numan Siddique <numans@ovn.org>
---
 northd/lflow-mgr.h |   38 +-
 northd/northd.c    | 1689 +++++++++++++++++++++++++++-----------------
 2 files changed, 1039 insertions(+), 688 deletions(-)

Comments

Dumitru Ceara Dec. 13, 2023, 10:47 a.m. UTC | #1
On 11/28/23 03:36, numans@ovn.org wrote:
> From: Numan Siddique <numans@ovn.org>
> 
> ovn_lflow_add* macros now expect 'lflow_ref' to be passed
> and it can be NULL too.
> 
> Signed-off-by: Numan Siddique <numans@ovn.org>
> ---

I didn't spot anything wrong with this commit.  It's probably fine to
include it as is in v4.

Regards,
Dumitru
Han Zhou Dec. 18, 2023, 7:10 a.m. UTC | #2
On Mon, Nov 27, 2023 at 6:38 PM <numans@ovn.org> wrote:
>
> From: Numan Siddique <numans@ovn.org>
>
> ovn_lflow_add* macros now expect 'lflow_ref' to be passed
> and it can be NULL too.

Thanks for taking the effort to make this tedious change.
Mostly it looks good to me except for a minor problem. Since the lflow_ref
is supposed to be associated with an object such as an ovn_port, a LB, or a
datapath, etc., the parameter should come from the object, such as
op->lflow_ref, instead of an extra parameter of the function, which is how
the function prototypes in build_lswitch_and_lrouter_iterate_by_lsp are
defined, which is good. However, the functions build_xxx_for_lb() added an
extra parameter lflow_ref, which is redundant, because those functions
already have a parameter lb_dps, which already contains lb_dps->lflow_ref.
An exception is build_lswitch_arp_nd_service_monitor, which has parameter
lb instead of lb_dps, but it would be more clear and unified to change the
parameter lb to lb_dps for this function. Similar strategy should be used
for other functions such as build_lbnat_lflows_iterate_by_lsp,
build_lbnat_lflows_iterate_by_lrp, and the functions in
build_lswitch_and_lrouter_iterate_by_ls and
build_lswitch_and_lrouter_iterate_by_lr, etc.

An additional question, did you think about the case when we need to handle
a second input of such lflows incrementally? It would require a lflow to be
added to two (or more) lflow_ref lists, the ovn_lflow_add() has only one
lflow_ref parameter. I understand that it is not in the scope of this
patch. I just hope we don't have to touch all this large amount of lines of
code again when that case needs to be handled.

Thanks,
Han

>
> Signed-off-by: Numan Siddique <numans@ovn.org>
> ---
>  northd/lflow-mgr.h |   38 +-
>  northd/northd.c    | 1689 +++++++++++++++++++++++++++-----------------
>  2 files changed, 1039 insertions(+), 688 deletions(-)
>
> diff --git a/northd/lflow-mgr.h b/northd/lflow-mgr.h
> index 7809c939e6..02b74aa131 100644
> --- a/northd/lflow-mgr.h
> +++ b/northd/lflow-mgr.h
> @@ -89,41 +89,27 @@ void lflow_table_add_lflow_default_drop(struct
lflow_table *,
>  /* Adds a row with the specified contents to the Logical_Flow table. */
>  #define ovn_lflow_add_with_hint__(LFLOW_TABLE, OD, STAGE, PRIORITY,
MATCH, \
>                                    ACTIONS, IN_OUT_PORT, CTRL_METER, \
> -                                  STAGE_HINT) \
> -    lflow_table_add_lflow(LFLOW_TABLE, OD, NULL, 0, STAGE, PRIORITY,
MATCH, \
> -                          ACTIONS, IN_OUT_PORT, CTRL_METER, STAGE_HINT, \
> -                          OVS_SOURCE_LOCATOR, NULL)
> -
> -#define ovn_lflow_add_with_lflow_ref_hint__(LFLOW_TABLE, OD, STAGE,
PRIORITY, \
> -                                            MATCH, ACTIONS, IN_OUT_PORT,
\
> -                                            CTRL_METER, STAGE_HINT,
LFLOW_REF)\
> +                                  STAGE_HINT, LFLOW_REF) \
>      lflow_table_add_lflow(LFLOW_TABLE, OD, NULL, 0, STAGE, PRIORITY,
MATCH, \
>                            ACTIONS, IN_OUT_PORT, CTRL_METER, STAGE_HINT, \
>                            OVS_SOURCE_LOCATOR, LFLOW_REF)
>
>  #define ovn_lflow_add_with_hint(LFLOW_TABLE, OD, STAGE, PRIORITY, MATCH,
\
> -                                ACTIONS, STAGE_HINT) \
> -    lflow_table_add_lflow(LFLOW_TABLE, OD, NULL, 0, STAGE, PRIORITY,
MATCH, \
> -                          ACTIONS, NULL, NULL, STAGE_HINT,  \
> -                          OVS_SOURCE_LOCATOR, NULL)
> -
> -#define ovn_lflow_add_with_lflow_ref_hint(LFLOW_TABLE, OD, STAGE,
PRIORITY, \
> -                                          MATCH, ACTIONS, STAGE_HINT, \
> -                                          LFLOW_REF) \
> +                                ACTIONS, STAGE_HINT, LFLOW_REF) \
>      lflow_table_add_lflow(LFLOW_TABLE, OD, NULL, 0, STAGE, PRIORITY,
MATCH, \
>                            ACTIONS, NULL, NULL, STAGE_HINT,  \
>                            OVS_SOURCE_LOCATOR, LFLOW_REF)
>
>  #define ovn_lflow_add_with_dp_group(LFLOW_TABLE, DP_BITMAP,
DP_BITMAP_LEN, \
>                                      STAGE, PRIORITY, MATCH, ACTIONS, \
> -                                    STAGE_HINT) \
> +                                    STAGE_HINT, LFLOW_REF) \
>      lflow_table_add_lflow(LFLOW_TABLE, NULL, DP_BITMAP, DP_BITMAP_LEN,
STAGE, \
>                            PRIORITY, MATCH, ACTIONS, NULL, NULL,
STAGE_HINT, \
> -                          OVS_SOURCE_LOCATOR, NULL)
> +                          OVS_SOURCE_LOCATOR, LFLOW_REF)
>
> -#define ovn_lflow_add_default_drop(LFLOW_TABLE, OD, STAGE)
     \
> +#define ovn_lflow_add_default_drop(LFLOW_TABLE, OD, STAGE, LFLOW_REF)   \
>      lflow_table_add_lflow_default_drop(LFLOW_TABLE, OD, STAGE, \
> -                                       OVS_SOURCE_LOCATOR, NULL)
> +                                       OVS_SOURCE_LOCATOR, LFLOW_REF)
>
>
>  /* This macro is similar to ovn_lflow_add_with_hint, except that it
requires
> @@ -143,20 +129,16 @@ void lflow_table_add_lflow_default_drop(struct
lflow_table *,
>                            ACTIONS, IN_OUT_PORT, NULL, STAGE_HINT, \
>                            OVS_SOURCE_LOCATOR, LFLOW_REF)
>
> -#define ovn_lflow_add(LFLOW_TABLE, OD, STAGE, PRIORITY, MATCH, ACTIONS) \
> -    lflow_table_add_lflow(LFLOW_TABLE, OD, NULL, 0, STAGE, PRIORITY,
MATCH, \
> -                          ACTIONS, NULL, NULL, NULL, OVS_SOURCE_LOCATOR,
NULL)
> -
> -#define ovn_lflow_add_with_lflow_ref(LFLOW_TABLE, OD, STAGE, PRIORITY,
MATCH, \
> -                                     ACTIONS, LFLOW_REF) \
> +#define ovn_lflow_add(LFLOW_TABLE, OD, STAGE, PRIORITY, MATCH, ACTIONS, \
> +                      LFLOW_REF) \
>      lflow_table_add_lflow(LFLOW_TABLE, OD, NULL, 0, STAGE, PRIORITY,
MATCH, \
>                            ACTIONS, NULL, NULL, NULL, OVS_SOURCE_LOCATOR,
\
>                            LFLOW_REF)
>
>  #define ovn_lflow_metered(LFLOW_TABLE, OD, STAGE, PRIORITY, MATCH,
ACTIONS, \
> -                          CTRL_METER) \
> +                          CTRL_METER, LFLOW_REF) \
>      ovn_lflow_add_with_hint__(LFLOW_TABLE, OD, STAGE, PRIORITY, MATCH, \
> -                              ACTIONS, NULL, CTRL_METER, NULL)
> +                              ACTIONS, NULL, CTRL_METER, NULL, LFLOW_REF)
>
>  struct sbrec_logical_dp_group;
>
> diff --git a/northd/northd.c b/northd/northd.c
> index 13d0db57e2..7c5fe60e9a 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -6063,13 +6063,16 @@ build_lswitch_learn_fdb_op(
>
>  static void
>  build_lswitch_learn_fdb_od(
> -        struct ovn_datapath *od, struct lflow_table *lflows)
> +        struct ovn_datapath *od, struct lflow_table *lflows,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbs);
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_LOOKUP_FDB, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_PUT_FDB, 0, "1", "next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_LOOKUP_FDB, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_PUT_FDB, 0, "1", "next;",
> +                  lflow_ref);
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 0, "1",
> -                  "outport = get_fdb(eth.dst); next;");
> +                  "outport = get_fdb(eth.dst); next;", lflow_ref);
>  }
>
>  /* Egress tables 8: Egress port security - IP (priority 0)
> @@ -6077,25 +6080,30 @@ build_lswitch_learn_fdb_od(
>   *                 (priority 100). */
>  static void
>  build_lswitch_output_port_sec_od(struct ovn_datapath *od,
> -                              struct lflow_table *lflows)
> +                              struct lflow_table *lflows,
> +                              struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbs);
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_CHECK_PORT_SEC, 100,
> -                  "eth.mcast", REGBIT_PORT_SEC_DROP" = 0; next;");
> +                  "eth.mcast", REGBIT_PORT_SEC_DROP" = 0; next;",
> +                  lflow_ref);
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_CHECK_PORT_SEC, 0, "1",
> -                  REGBIT_PORT_SEC_DROP" = check_out_port_sec(); next;");
> +                  REGBIT_PORT_SEC_DROP" = check_out_port_sec(); next;",
> +                  lflow_ref);
>
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_APPLY_PORT_SEC, 50,
> -                  REGBIT_PORT_SEC_DROP" == 1", debug_drop_action());
> +                  REGBIT_PORT_SEC_DROP" == 1", debug_drop_action(),
> +                  lflow_ref);
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_APPLY_PORT_SEC, 0,
> -                  "1", "output;");
> +                  "1", "output;", lflow_ref);
>  }
>
>  static void
>  skip_port_from_conntrack(const struct ovn_datapath *od, struct ovn_port
*op,
>                           bool has_stateful_acl, enum ovn_stage in_stage,
>                           enum ovn_stage out_stage, uint16_t priority,
> -                         struct lflow_table *lflows)
> +                         struct lflow_table *lflows,
> +                         struct lflow_ref *lflow_ref)
>  {
>      /* Can't use ct() for router ports. Consider the following
configuration:
>       * lp1(10.0.0.2) on hostA--ls1--lr0--ls2--lp2(10.0.1.2) on hostB,
For a
> @@ -6117,10 +6125,10 @@ skip_port_from_conntrack(const struct
ovn_datapath *od, struct ovn_port *op,
>
>      ovn_lflow_add_with_lport_and_hint(lflows, od, in_stage, priority,
>                                        ingress_match, ingress_action,
> -                                      op->key, &op->nbsp->header_, NULL);
> +                                      op->key, &op->nbsp->header_,
lflow_ref);
>      ovn_lflow_add_with_lport_and_hint(lflows, od, out_stage, priority,
>                                        egress_match, egress_action,
> -                                      op->key, &op->nbsp->header_, NULL);
> +                                      op->key, &op->nbsp->header_,
lflow_ref);
>
>      free(ingress_match);
>      free(egress_match);
> @@ -6129,7 +6137,8 @@ skip_port_from_conntrack(const struct ovn_datapath
*od, struct ovn_port *op,
>  static void
>  build_stateless_filter(const struct ovn_datapath *od,
>                         const struct nbrec_acl *acl,
> -                       struct lflow_table *lflows)
> +                       struct lflow_table *lflows,
> +                       struct lflow_ref *lflow_ref)
>  {
>      const char *action = REGBIT_ACL_STATELESS" = 1; next;";
>      if (!strcmp(acl->direction, "from-lport")) {
> @@ -6137,25 +6146,28 @@ build_stateless_filter(const struct ovn_datapath
*od,
>                                  acl->priority + OVN_ACL_PRI_OFFSET,
>                                  acl->match,
>                                  action,
> -                                &acl->header_);
> +                                &acl->header_,
> +                                lflow_ref);
>      } else {
>          ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL,
>                                  acl->priority + OVN_ACL_PRI_OFFSET,
>                                  acl->match,
>                                  action,
> -                                &acl->header_);
> +                                &acl->header_,
> +                                lflow_ref);
>      }
>  }
>
>  static void
>  build_stateless_filters(const struct ovn_datapath *od,
>                          const struct ls_port_group_table *ls_port_groups,
> -                        struct lflow_table *lflows)
> +                        struct lflow_table *lflows,
> +                        struct lflow_ref *lflow_ref)
>  {
>      for (size_t i = 0; i < od->nbs->n_acls; i++) {
>          const struct nbrec_acl *acl = od->nbs->acls[i];
>          if (!strcmp(acl->action, "allow-stateless")) {
> -            build_stateless_filter(od, acl, lflows);
> +            build_stateless_filter(od, acl, lflows, lflow_ref);
>          }
>      }
>
> @@ -6171,31 +6183,37 @@ build_stateless_filters(const struct ovn_datapath
*od,
>              const struct nbrec_acl *acl = ls_pg_rec->nb_pg->acls[i];
>
>              if (!strcmp(acl->action, "allow-stateless")) {
> -                build_stateless_filter(od, acl, lflows);
> +                build_stateless_filter(od, acl, lflows, lflow_ref);
>              }
>          }
>      }
>  }
>
>  static void
> -build_pre_acls(struct ovn_datapath *od, struct lflow_table *lflows)
> +build_pre_acls(struct ovn_datapath *od, struct lflow_table *lflows,
> +               struct lflow_ref *lflow_ref)
>  {
>      /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are
>       * allowed by default. */
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 0, "1", "next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 0, "1", "next;",
> +                  lflow_ref);
>
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
> -                  "eth.dst == $svc_monitor_mac", "next;");
> +                  "eth.dst == $svc_monitor_mac", "next;",
> +                  lflow_ref);
>
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
> -                  "eth.src == $svc_monitor_mac", "next;");
> +                  "eth.src == $svc_monitor_mac", "next;",
> +                  lflow_ref);
>  }
>
>  static void
>  build_ls_stateful_rec_pre_acls(const struct ls_stateful_record
*ls_sful_rec,
>                               const struct ls_port_group_table
*ls_port_groups,
> -                             struct lflow_table *lflows)
> +                             struct lflow_table *lflows,
> +                             struct lflow_ref *lflow_ref)
>  {
>      const struct ovn_datapath *od = ls_sful_rec->od;
>
> @@ -6206,17 +6224,17 @@ build_ls_stateful_rec_pre_acls(const struct
ls_stateful_record *ls_sful_rec,
>          for (size_t i = 0; i < od->n_router_ports; i++) {
>              skip_port_from_conntrack(od, od->router_ports[i], true,
>                                       S_SWITCH_IN_PRE_ACL,
S_SWITCH_OUT_PRE_ACL,
> -                                     110, lflows);
> +                                     110, lflows, lflow_ref);
>          }
>          for (size_t i = 0; i < od->n_localnet_ports; i++) {
>              skip_port_from_conntrack(od, od->localnet_ports[i], true,
>                                       S_SWITCH_IN_PRE_ACL,
>                                       S_SWITCH_OUT_PRE_ACL,
> -                                     110, lflows);
> +                                     110, lflows, lflow_ref);
>          }
>
>          /* stateless filters always take precedence over stateful ACLs.
*/
> -        build_stateless_filters(od, ls_port_groups, lflows);
> +        build_stateless_filters(od, ls_port_groups, lflows, lflow_ref);
>
>          /* Ingress and Egress Pre-ACL Table (Priority 110).
>           *
> @@ -6224,16 +6242,18 @@ build_ls_stateful_rec_pre_acls(const struct
ls_stateful_record *ls_sful_rec,
>           * unreachable packets. */
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
>                        "nd || nd_rs || nd_ra || mldv1 || mldv2 || "
> -                      "(udp && udp.src == 546 && udp.dst == 547)",
"next;");
> +                      "(udp && udp.src == 546 && udp.dst == 547)",
"next;",
> +                      lflow_ref);
>          ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
>                        "nd || nd_rs || nd_ra || mldv1 || mldv2 || "
> -                      "(udp && udp.src == 546 && udp.dst == 547)",
"next;");
> +                      "(udp && udp.src == 546 && udp.dst == 547)",
"next;",
> +                      lflow_ref);
>
>          /* Do not send multicast packets to conntrack. */
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, "eth.mcast",
> -                      "next;");
> +                      "next;", lflow_ref);
>          ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, "eth.mcast",
> -                      "next;");
> +                      "next;", lflow_ref);
>
>          /* Ingress and Egress Pre-ACL Table (Priority 100).
>           *
> @@ -6244,13 +6264,15 @@ build_ls_stateful_rec_pre_acls(const struct
ls_stateful_record *ls_sful_rec,
>           * 'REGBIT_CONNTRACK_DEFRAG' is set to let the pre-stateful
table send
>           * it to conntrack for tracking and defragmentation. */
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 100, "ip",
> -                      REGBIT_CONNTRACK_DEFRAG" = 1; next;");
> +                      REGBIT_CONNTRACK_DEFRAG" = 1; next;",
> +                      lflow_ref);
>          ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 100, "ip",
> -                      REGBIT_CONNTRACK_DEFRAG" = 1; next;");
> +                      REGBIT_CONNTRACK_DEFRAG" = 1; next;",
> +                      lflow_ref);
>      } else if (ls_sful_rec->has_lb_vip) {
>          /* We'll build stateless filters if there are LB rules so that
>           * the stateless flows are not tracked in pre-lb. */
> -         build_stateless_filters(od, ls_port_groups, lflows);
> +         build_stateless_filters(od, ls_port_groups, lflows, lflow_ref);
>      }
>  }
>
> @@ -6314,7 +6336,8 @@ build_empty_lb_event_flow(struct ovn_lb_vip *lb_vip,
>  static void
>  build_interconn_mcast_snoop_flows(struct ovn_datapath *od,
>                                    const struct shash *meter_groups,
> -                                  struct lflow_table *lflows)
> +                                  struct lflow_table *lflows,
> +                                   struct lflow_ref *lflow_ref)
>  {
>      struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw;
>      if (!mcast_sw_info->enabled
> @@ -6333,7 +6356,8 @@ build_interconn_mcast_snoop_flows(struct
ovn_datapath *od,
>          ovn_lflow_metered(lflows, od, S_SWITCH_OUT_PRE_LB, 120, match,
>                            "clone { igmp; }; next;",
>                            copp_meter_get(COPP_IGMP, od->nbs->copp,
> -                                         meter_groups));
> +                                         meter_groups),
> +                          lflow_ref);
>          free(match);
>
>          /* Punt MLD traffic to controller. */
> @@ -6341,50 +6365,54 @@ build_interconn_mcast_snoop_flows(struct
ovn_datapath *od,
>          ovn_lflow_metered(lflows, od, S_SWITCH_OUT_PRE_LB, 120, match,
>                            "clone { igmp; }; next;",
>                            copp_meter_get(COPP_IGMP, od->nbs->copp,
> -                                         meter_groups));
> +                                         meter_groups),
> +                          lflow_ref);
>          free(match);
>      }
>  }
>
>  static void
>  build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups,
> -             struct lflow_table *lflows)
> +             struct lflow_table *lflows, struct lflow_ref *lflow_ref)
>  {
>      /* Handle IGMP/MLD packets crossing AZs. */
> -    build_interconn_mcast_snoop_flows(od, meter_groups, lflows);
> +    build_interconn_mcast_snoop_flows(od, meter_groups, lflows,
lflow_ref);
>
>      /* Do not send multicast packets to conntrack */
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, "eth.mcast",
"next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, "eth.mcast",
"next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, "eth.mcast",
"next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, "eth.mcast",
"next;",
> +                  lflow_ref);
>
>      /* Do not send ND packets to conntrack */
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110,
>                    "nd || nd_rs || nd_ra || mldv1 || mldv2",
> -                  "next;");
> +                  "next;", lflow_ref);
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110,
>                    "nd || nd_rs || nd_ra || mldv1 || mldv2",
> -                  "next;");
> +                  "next;", lflow_ref);
>
>      /* Do not send service monitor packets to conntrack. */
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110,
> -                  "eth.dst == $svc_monitor_mac", "next;");
> +                  "eth.dst == $svc_monitor_mac", "next;", lflow_ref);
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110,
> -                  "eth.src == $svc_monitor_mac", "next;");
> +                  "eth.src == $svc_monitor_mac", "next;", lflow_ref);
>
>      /* Allow all packets to go to next tables by default. */
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 0, "1", "next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 0, "1", "next;",
lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 0, "1", "next;",
lflow_ref);
>
>      /* Do not send statless flows via conntrack */
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110,
> -                  REGBIT_ACL_STATELESS" == 1", "next;");
> +                  REGBIT_ACL_STATELESS" == 1", "next;", lflow_ref);
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110,
> -                  REGBIT_ACL_STATELESS" == 1", "next;");
> +                  REGBIT_ACL_STATELESS" == 1", "next;", lflow_ref);
>  }
>
>  static void
>  build_ls_stateful_rec_pre_lb(const struct ls_stateful_record
*ls_stateful_rec,
> -                             struct lflow_table *lflows)
> +                             struct lflow_table *lflows,
> +                             struct lflow_ref *lflow_ref)
>  {
>      const struct ovn_datapath *od = ls_stateful_rec->od;
>
> @@ -6392,7 +6420,7 @@ build_ls_stateful_rec_pre_lb(const struct
ls_stateful_record *ls_stateful_rec,
>          skip_port_from_conntrack(od, od->router_ports[i],
>                                   ls_stateful_rec->has_stateful_acl,
>                                   S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB,
> -                                 110, lflows);
> +                                 110, lflows, lflow_ref);
>      }
>
>      /* Localnet ports have no need for going through conntrack, unless
> @@ -6405,7 +6433,7 @@ build_ls_stateful_rec_pre_lb(const struct
ls_stateful_record *ls_stateful_rec,
>              skip_port_from_conntrack(od, od->localnet_ports[i],
>                                       ls_stateful_rec->has_stateful_acl,
>                                       S_SWITCH_IN_PRE_LB,
S_SWITCH_OUT_PRE_LB,
> -                                     110, lflows);
> +                                     110, lflows, lflow_ref);
>          }
>      }
>
> @@ -6441,21 +6469,26 @@ build_ls_stateful_rec_pre_lb(const struct
ls_stateful_record *ls_stateful_rec,
>       */
>      if (ls_stateful_rec->has_lb_vip) {
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB,
> -                      100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;");
> +                      100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;",
> +                      lflow_ref);
>          ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB,
> -                      100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;");
> +                      100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;",
> +                      lflow_ref);
>      }
>  }
>
>  static void
>  build_pre_stateful(struct ovn_datapath *od,
>                     const struct chassis_features *features,
> -                   struct lflow_table *lflows)
> +                   struct lflow_table *lflows,
> +                   struct lflow_ref *lflow_ref)
>  {
>      /* Ingress and Egress pre-stateful Table (Priority 0): Packets are
>       * allowed by default. */
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 0, "1",
"next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 0, "1", "next;",
> +                  lflow_ref);
>
>      /* Note: priority-120 flows are added in
build_lb_rules_pre_stateful(). */
>
> @@ -6464,25 +6497,30 @@ build_pre_stateful(struct ovn_datapath *od,
>                                 : "ct_lb;";
>
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 110,
> -                  REGBIT_CONNTRACK_NAT" == 1", ct_lb_action);
> +                  REGBIT_CONNTRACK_NAT" == 1", ct_lb_action,
> +                  lflow_ref);
>
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 110,
> -                  REGBIT_CONNTRACK_NAT" == 1", ct_lb_action);
> +                  REGBIT_CONNTRACK_NAT" == 1", ct_lb_action,
> +                  lflow_ref);
>
>      /* If REGBIT_CONNTRACK_DEFRAG is set as 1, then the packets should be
>       * sent to conntrack for tracking and defragmentation. */
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 100,
> -                  REGBIT_CONNTRACK_DEFRAG" == 1", "ct_next;");
> +                  REGBIT_CONNTRACK_DEFRAG" == 1", "ct_next;",
> +                  lflow_ref);
>
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 100,
> -                  REGBIT_CONNTRACK_DEFRAG" == 1", "ct_next;");
> +                  REGBIT_CONNTRACK_DEFRAG" == 1", "ct_next;",
> +                  lflow_ref);
>
>  }
>
>  static void
>  build_acl_hints(const struct ls_stateful_record *ls_sful_rec,
>                  const struct chassis_features *features,
> -                struct lflow_table *lflows)
> +                struct lflow_table *lflows,
> +                struct lflow_ref *lflow_ref)
>  {
>      const struct ovn_datapath *od = ls_sful_rec->od;
>
> @@ -6510,9 +6548,10 @@ build_acl_hints(const struct ls_stateful_record
*ls_sful_rec,
>
>          /* In any case, advance to the next stage. */
>          if (!ls_sful_rec->has_acls && !ls_sful_rec->has_lb_vip) {
> -            ovn_lflow_add(lflows, od, stage, UINT16_MAX, "1", "next;");
> +            ovn_lflow_add(lflows, od, stage, UINT16_MAX, "1", "next;",
> +                          lflow_ref);
>          } else {
> -            ovn_lflow_add(lflows, od, stage, 0, "1", "next;");
> +            ovn_lflow_add(lflows, od, stage, 0, "1", "next;", lflow_ref);
>          }
>
>          if (!ls_sful_rec->has_stateful_acl && !ls_sful_rec->has_lb_vip) {
> @@ -6526,7 +6565,7 @@ build_acl_hints(const struct ls_stateful_record
*ls_sful_rec,
>          ovn_lflow_add(lflows, od, stage, 7, "ct.new && !ct.est",
>                        REGBIT_ACL_HINT_ALLOW_NEW " = 1; "
>                        REGBIT_ACL_HINT_DROP " = 1; "
> -                      "next;");
> +                      "next;", lflow_ref);
>
>          /* Already established connections in the "request" direction
that
>           * are already marked as "blocked" may hit either:
> @@ -6542,13 +6581,13 @@ build_acl_hints(const struct ls_stateful_record
*ls_sful_rec,
>          ovn_lflow_add(lflows, od, stage, 6, match,
>                        REGBIT_ACL_HINT_ALLOW_NEW " = 1; "
>                        REGBIT_ACL_HINT_DROP " = 1; "
> -                      "next;");
> +                      "next;", lflow_ref);
>
>          /* Not tracked traffic can either be allowed or dropped. */
>          ovn_lflow_add(lflows, od, stage, 5, "!ct.trk",
>                        REGBIT_ACL_HINT_ALLOW " = 1; "
>                        REGBIT_ACL_HINT_DROP " = 1; "
> -                      "next;");
> +                      "next;", lflow_ref);
>
>          /* Already established connections in the "request" direction
may hit
>           * either:
> @@ -6564,20 +6603,20 @@ build_acl_hints(const struct ls_stateful_record
*ls_sful_rec,
>          ovn_lflow_add(lflows, od, stage, 4, match,
>                        REGBIT_ACL_HINT_ALLOW " = 1; "
>                        REGBIT_ACL_HINT_BLOCK " = 1; "
> -                      "next;");
> +                      "next;", lflow_ref);
>
>          /* Not established or established and already blocked
connections may
>           * hit drop ACLs.
>           */
>          ovn_lflow_add(lflows, od, stage, 3, "!ct.est",
>                        REGBIT_ACL_HINT_DROP " = 1; "
> -                      "next;");
> +                      "next;", lflow_ref);
>          match = features->ct_no_masked_label
>                  ? "ct.est && ct_mark.blocked == 1"
>                  : "ct.est && ct_label.blocked == 1";
>          ovn_lflow_add(lflows, od, stage, 2, match,
>                        REGBIT_ACL_HINT_DROP " = 1; "
> -                      "next;");
> +                      "next;", lflow_ref);
>
>          /* Established connections that were previously allowed might hit
>           * drop ACLs in which case the connection must be committed with
> @@ -6588,7 +6627,7 @@ build_acl_hints(const struct ls_stateful_record
*ls_sful_rec,
>                  : "ct.est && ct_label.blocked == 0";
>          ovn_lflow_add(lflows, od, stage, 1, match,
>                        REGBIT_ACL_HINT_BLOCK " = 1; "
> -                      "next;");
> +                      "next;", lflow_ref);
>      }
>  }
>
> @@ -6654,7 +6693,8 @@ static void
>  consider_acl(struct lflow_table *lflows, const struct ovn_datapath *od,
>               const struct nbrec_acl *acl, bool has_stateful,
>               bool ct_masked_mark, const struct shash *meter_groups,
> -             uint64_t max_acl_tier, struct ds *match, struct ds *actions)
> +             uint64_t max_acl_tier, struct ds *match, struct ds *actions,
> +             struct lflow_ref *lflow_ref)
>  {
>      const char *ct_blocked_match = ct_masked_mark
>                                     ? "ct_mark.blocked"
> @@ -6703,7 +6743,7 @@ consider_acl(struct lflow_table *lflows, const
struct ovn_datapath *od,
>          ds_put_format(match, "(%s)", acl->match);
>          ovn_lflow_add_with_hint(lflows, od, stage, priority,
>                                  ds_cstr(match), ds_cstr(actions),
> -                                &acl->header_);
> +                                &acl->header_, lflow_ref);
>          return;
>      }
>
> @@ -6740,7 +6780,7 @@ consider_acl(struct lflow_table *lflows, const
struct ovn_datapath *od,
>          ds_put_cstr(actions, "next;");
>          ovn_lflow_add_with_hint(lflows, od, stage, priority,
>                                  ds_cstr(match), ds_cstr(actions),
> -                                &acl->header_);
> +                                &acl->header_, lflow_ref);
>
>          /* Match on traffic in the request direction for an established
>           * connection tracking entry that has not been marked for
> @@ -6762,7 +6802,7 @@ consider_acl(struct lflow_table *lflows, const
struct ovn_datapath *od,
>          ds_put_cstr(actions, "next;");
>          ovn_lflow_add_with_hint(lflows, od, stage, priority,
>                                  ds_cstr(match), ds_cstr(actions),
> -                                &acl->header_);
> +                                &acl->header_, lflow_ref);
>      } else if (!strcmp(acl->action, "drop")
>                 || !strcmp(acl->action, "reject")) {
>          /* The implementation of "drop" differs if stateful ACLs are in
> @@ -6779,7 +6819,7 @@ consider_acl(struct lflow_table *lflows, const
struct ovn_datapath *od,
>          ds_put_cstr(actions, "next;");
>          ovn_lflow_add_with_hint(lflows, od, stage, priority,
>                                  ds_cstr(match), ds_cstr(actions),
> -                                &acl->header_);
> +                                &acl->header_, lflow_ref);
>          /* For an existing connection without ct_mark.blocked set, we've
>           * encountered a policy change. ACLs previously allowed
>           * this connection and we committed the connection tracking
> @@ -6800,7 +6840,7 @@ consider_acl(struct lflow_table *lflows, const
struct ovn_datapath *od,
>                        ct_blocked_match);
>          ovn_lflow_add_with_hint(lflows, od, stage, priority,
>                                  ds_cstr(match), ds_cstr(actions),
> -                                &acl->header_);
> +                                &acl->header_, lflow_ref);
>      }
>  }
>
> @@ -6883,7 +6923,8 @@ build_acl_action_lflows(const struct
ls_stateful_record *ls_stateful_rec,
>                          const char *default_acl_action,
>                          const struct shash *meter_groups,
>                          struct ds *match,
> -                        struct ds *actions)
> +                        struct ds *actions,
> +                        struct lflow_ref *lflow_ref)
>  {
>      const struct ovn_datapath *od = ls_stateful_rec->od;
>
> @@ -6906,18 +6947,20 @@ build_acl_action_lflows(const struct
ls_stateful_record *ls_stateful_rec,
>      for (size_t i = 0; i < ARRAY_SIZE(stages); i++) {
>          enum ovn_stage stage = stages[i];
>          if (!ls_stateful_rec->has_acls) {
> -            ovn_lflow_add(lflows, od, stage, 0, "1", "next;");
> +            ovn_lflow_add(lflows, od, stage, 0, "1", "next;", lflow_ref);
>              continue;
>          }
>          ds_truncate(actions, verdict_len);
>          ds_put_cstr(actions, "next;");
>          ovn_lflow_add(lflows, od, stage, 1000,
> -                      REGBIT_ACL_VERDICT_ALLOW " == 1",
ds_cstr(actions));
> +                      REGBIT_ACL_VERDICT_ALLOW " == 1", ds_cstr(actions),
> +                      lflow_ref);
>          ds_truncate(actions, verdict_len);
>          ds_put_cstr(actions, debug_implicit_drop_action());
>          ovn_lflow_add(lflows, od, stage, 1000,
>                        REGBIT_ACL_VERDICT_DROP " == 1",
> -                      ds_cstr(actions));
> +                      ds_cstr(actions),
> +                      lflow_ref);
>          bool ingress = ovn_stage_get_pipeline(stage) == P_IN;
>
>          ds_truncate(actions, verdict_len);
> @@ -6933,11 +6976,11 @@ build_acl_action_lflows(const struct
ls_stateful_record *ls_stateful_rec,
>          ovn_lflow_metered(lflows, od, stage, 1000,
>                            REGBIT_ACL_VERDICT_REJECT " == 1",
ds_cstr(actions),
>                            copp_meter_get(COPP_REJECT, od->nbs->copp,
> -                          meter_groups));
> +                          meter_groups), lflow_ref);
>
>          ds_truncate(actions, verdict_len);
>          ds_put_cstr(actions, default_acl_action);
> -        ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions));
> +        ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions),
lflow_ref);
>
>          struct ds tier_actions = DS_EMPTY_INITIALIZER;
>          for (size_t j = 0; j < ls_stateful_rec->max_acl_tier; j++) {
> @@ -6949,7 +6992,7 @@ build_acl_action_lflows(const struct
ls_stateful_record *ls_stateful_rec,
>                            j + 1, ingress ? "ingress" : "egress",
>                            ovn_stage_get_table(stage) - 1);
>              ovn_lflow_add(lflows, od, stage, 500, ds_cstr(match),
> -                         ds_cstr(&tier_actions));
> +                         ds_cstr(&tier_actions), lflow_ref);
>          }
>          ds_destroy(&tier_actions);
>      }
> @@ -6961,7 +7004,8 @@ build_acl_log_related_flows(const struct
ovn_datapath *od,
>                              const struct nbrec_acl *acl, bool
has_stateful,
>                              bool ct_masked_mark,
>                              const struct shash *meter_groups,
> -                            struct ds *match, struct ds *actions)
> +                            struct ds *match, struct ds *actions,
> +                            struct lflow_ref *lflow_ref)
>  {
>      /* Related and reply traffic are universally allowed by priority
>       * 65532 flows created in build_acls(). If logging is enabled on
> @@ -7015,7 +7059,7 @@ build_acl_log_related_flows(const struct
ovn_datapath *od,
>      ovn_lflow_add_with_hint(lflows, od, log_related_stage,
>                              UINT16_MAX - 2,
>                              ds_cstr(match), ds_cstr(actions),
> -                            &acl->header_);
> +                            &acl->header_, lflow_ref);
>
>      ds_clear(match);
>      ds_put_format(match, "!ct.est && ct.rel && !ct.new%s && "
> @@ -7026,7 +7070,7 @@ build_acl_log_related_flows(const struct
ovn_datapath *od,
>      ovn_lflow_add_with_hint(lflows, od, log_related_stage,
>                              UINT16_MAX - 2,
>                              ds_cstr(match), ds_cstr(actions),
> -                            &acl->header_);
> +                            &acl->header_, lflow_ref);
>  }
>
>  static void
> @@ -7034,7 +7078,8 @@ build_acls(const struct ls_stateful_record
*ls_stateful_rec,
>             const struct chassis_features *features,
>             struct lflow_table *lflows,
>             const struct ls_port_group_table *ls_port_groups,
> -           const struct shash *meter_groups)
> +           const struct shash *meter_groups,
> +           struct lflow_ref *lflow_ref)
>  {
>      const struct ovn_datapath *od = ls_stateful_rec->od;
>
> @@ -7059,20 +7104,24 @@ build_acls(const struct ls_stateful_record
*ls_stateful_rec,
>      if (!ls_stateful_rec->has_acls) {
>          if (!ls_stateful_rec->has_lb_vip) {
>              ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX,
"1",
> -                          "next;");
> +                          "next;", lflow_ref);
>              ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX,
"1",
> -                          "next;");
> +                          "next;", lflow_ref);
>          } else {
> -            ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 0, "1",
"next;");
> -            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 0, "1",
"next;");
> +            ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 0, "1",
"next;",
> +                          lflow_ref);
> +            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 0, "1",
"next;",
> +                          lflow_ref);
>          }
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL, 0, "1",
> -                      "next;");
> +                      "next;", lflow_ref);
>      } else {
> -        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 0, "1", "next;");
> -        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 0, "1",
"next;");
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 0, "1", "next;",
> +                      lflow_ref);
> +        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 0, "1", "next;",
> +                      lflow_ref);
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL, 0, "1",
> -                      "next;");
> +                      "next;", lflow_ref);
>      }
>
>
> @@ -7104,19 +7153,21 @@ build_acls(const struct ls_stateful_record
*ls_stateful_rec,
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 1,
>                        ds_cstr(&match),
>                        REGBIT_CONNTRACK_COMMIT" = 1; "
> -                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
> +                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;",
> +                      lflow_ref);
>          ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 1,
>                        ds_cstr(&match),
>                        REGBIT_CONNTRACK_COMMIT" = 1; "
> -                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
> +                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;",
> +                      lflow_ref);
>
>          const char *next_action = default_acl_drop
>                               ? "next;"
>                               : REGBIT_CONNTRACK_COMMIT" = 1; next;";
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 1, "ip &&
!ct.est",
> -                      next_action);
> +                      next_action, lflow_ref);
>          ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 1, "ip &&
!ct.est",
> -                      next_action);
> +                      next_action, lflow_ref);
>
>          /* Ingress and Egress ACL Table (Priority 65532).
>           *
> @@ -7130,9 +7181,11 @@ build_acls(const struct ls_stateful_record
*ls_stateful_rec,
>                        use_ct_inv_match ? "ct.inv || " : "",
>                        ct_blocked_match);
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
> -                      ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1;
next;");
> +                      ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1;
next;",
> +                      lflow_ref);
>          ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
> -                      ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1;
next;");
> +                      ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1;
next;",
> +                      lflow_ref);
>
>          /* Ingress and Egress ACL Table (Priority 65535 - 3).
>           *
> @@ -7152,10 +7205,12 @@ build_acls(const struct ls_stateful_record
*ls_stateful_rec,
>                        ds_cstr(&match), REGBIT_ACL_HINT_DROP" = 0; "
>                        REGBIT_ACL_HINT_BLOCK" = 0; "
>                        REGBIT_ACL_HINT_ALLOW_REL" = 1; "
> -                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
> +                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;",
> +                      lflow_ref);
>          ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
>                        ds_cstr(&match),
> -                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
> +                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
> +                      lflow_ref);
>
>          /* Ingress and Egress ACL Table (Priority 65535).
>           *
> @@ -7184,15 +7239,16 @@ build_acls(const struct ls_stateful_record
*ls_stateful_rec,
>                        use_ct_inv_match ? " && !ct.inv" : "",
>                        ct_blocked_match);
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
> -                      ds_cstr(&match), ct_in_acl_action);
> +                      ds_cstr(&match), ct_in_acl_action, lflow_ref);
>          ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
> -                      ds_cstr(&match), ct_out_acl_action);
> +                      ds_cstr(&match), ct_out_acl_action, lflow_ref);
>          /* Reply and related traffic matched by an "allow-related" ACL
>           * should be allowed in the ls_in_acl_after_lb stage too. */
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL,
>                        UINT16_MAX - 3,
>                        REGBIT_ACL_HINT_ALLOW_REL" == 1",
> -                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
> +                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
> +                      lflow_ref);
>      }
>
>      /* Ingress and Egress ACL Table (Priority 65532).
> @@ -7204,24 +7260,28 @@ build_acls(const struct ls_stateful_record
*ls_stateful_rec,
>       * https://bugzilla.kernel.org/show_bug.cgi?id=11797. */
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
>                    IPV6_CT_OMIT_MATCH,
> -                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
> +                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
> +                  lflow_ref);
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
>                    IPV6_CT_OMIT_MATCH,
> -                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
> +                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
> +                  lflow_ref);
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL, UINT16_MAX
- 3,
>                    IPV6_CT_OMIT_MATCH,
> -                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
> +                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
> +                  lflow_ref);
>
>      /* Ingress or Egress ACL Table (Various priorities). */
>      for (size_t i = 0; i < od->nbs->n_acls; i++) {
>          struct nbrec_acl *acl = od->nbs->acls[i];
>          build_acl_log_related_flows(od, lflows, acl, has_stateful,
>                                      features->ct_no_masked_label,
> -                                    meter_groups, &match, &actions);
> +                                    meter_groups, &match, &actions,
> +                                    lflow_ref);
>          consider_acl(lflows, od, acl, has_stateful,
>                       features->ct_no_masked_label,
>                       meter_groups, ls_stateful_rec->max_acl_tier,
> -                     &match, &actions);
> +                     &match, &actions, lflow_ref);
>      }
>
>      const struct ls_port_group *ls_pg =
> @@ -7234,11 +7294,12 @@ build_acls(const struct ls_stateful_record
*ls_stateful_rec,
>
>                  build_acl_log_related_flows(od, lflows, acl,
has_stateful,
>                                              features->ct_no_masked_label,
> -                                            meter_groups, &match,
&actions);
> +                                            meter_groups, &match,
&actions,
> +                                            lflow_ref);
>                  consider_acl(lflows, od, acl, has_stateful,
>                               features->ct_no_masked_label,
>                               meter_groups, ls_stateful_rec->max_acl_tier,
> -                             &match, &actions);
> +                             &match, &actions, lflow_ref);
>              }
>          }
>      }
> @@ -7253,7 +7314,7 @@ build_acls(const struct ls_stateful_record
*ls_stateful_rec,
>                           : REGBIT_ACL_VERDICT_ALLOW" = 1; next;";
>          ovn_lflow_add(
>              lflows, od, S_SWITCH_OUT_ACL_EVAL, 34000, "udp.src == 53",
> -            dns_actions);
> +            dns_actions, lflow_ref);
>      }
>
>      if (ls_stateful_rec->has_acls || ls_stateful_rec->has_lb_vip) {
> @@ -7261,30 +7322,37 @@ build_acls(const struct ls_stateful_record
*ls_stateful_rec,
>          * packets to skip applying ingress ACLs. */
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 34000,
>                      "eth.dst == $svc_monitor_mac",
> -                    REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
> +                    REGBIT_ACL_VERDICT_ALLOW" = 1; next;",
> +                    lflow_ref);
>
>          /* Add a 34000 priority flow to advance the service monitor
packets
>          * generated by ovn-controller to skip applying egress ACLs. */
>          ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 34000,
>                      "eth.src == $svc_monitor_mac",
> -                    REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
> +                    REGBIT_ACL_VERDICT_ALLOW" = 1; next;",
> +                    lflow_ref);
>      }
>
>      build_acl_action_lflows(ls_stateful_rec, lflows, default_acl_action,
> -                            meter_groups, &match, &actions);
> +                            meter_groups, &match, &actions, lflow_ref);
>
>      ds_destroy(&match);
>      ds_destroy(&actions);
>  }
>
>  static void
> -build_qos(struct ovn_datapath *od, struct lflow_table *lflows) {
> +build_qos(struct ovn_datapath *od, struct lflow_table *lflows,
> +          struct lflow_ref *lflow_ref) {
>      struct ds action = DS_EMPTY_INITIALIZER;
>
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_QOS_MARK, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_OUT_QOS_MARK, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_QOS_METER, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_OUT_QOS_METER, 0, "1", "next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_QOS_MARK, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_OUT_QOS_MARK, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_QOS_METER, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_OUT_QOS_METER, 0, "1", "next;",
> +                  lflow_ref);
>
>      for (size_t i = 0; i < od->nbs->n_qos_rules; i++) {
>          struct nbrec_qos *qos = od->nbs->qos_rules[i];
> @@ -7301,7 +7369,7 @@ build_qos(struct ovn_datapath *od, struct
lflow_table *lflows) {
>                  ovn_lflow_add_with_hint(lflows, od, stage,
>                                          qos->priority,
>                                          qos->match, ds_cstr(&action),
> -                                        &qos->header_);
> +                                        &qos->header_, lflow_ref);
>              }
>          }
>
> @@ -7332,7 +7400,7 @@ build_qos(struct ovn_datapath *od, struct
lflow_table *lflows) {
>              ovn_lflow_add_with_hint(lflows, od, stage,
>                                      qos->priority,
>                                      qos->match, ds_cstr(&action),
> -                                    &qos->header_);
> +                                    &qos->header_, lflow_ref);
>          }
>      }
>      ds_destroy(&action);
> @@ -7343,7 +7411,8 @@ build_lb_rules_pre_stateful(struct lflow_table
*lflows,
>                              struct ovn_lb_datapaths *lb_dps,
>                              bool ct_lb_mark,
>                              const struct ovn_datapaths *ls_datapaths,
> -                            struct ds *match, struct ds *action)
> +                            struct ds *match, struct ds *action,
> +                            struct lflow_ref *lflow_ref)
>  {
>      if (!lb_dps->n_nb_ls) {
>          return;
> @@ -7397,7 +7466,7 @@ build_lb_rules_pre_stateful(struct lflow_table
*lflows,
>          ovn_lflow_add_with_dp_group(
>              lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths),
>              S_SWITCH_IN_PRE_STATEFUL, 120, ds_cstr(match),
ds_cstr(action),
> -            &lb->nlb->header_);
> +            &lb->nlb->header_, lflow_ref);
>      }
>  }
>
> @@ -7445,7 +7514,8 @@ build_lb_affinity_lr_flows(struct lflow_table
*lflows,
>                             const struct ovn_northd_lb *lb,
>                             struct ovn_lb_vip *lb_vip, char *new_lb_match,
>                             char *lb_action, const unsigned long
*dp_bitmap,
> -                           const struct ovn_datapaths *lr_datapaths)
> +                           const struct ovn_datapaths *lr_datapaths,
> +                           struct lflow_ref *lflow_ref)
>  {
>      if (!lb->affinity_timeout ||
>          bitmap_is_all_zeros(dp_bitmap, ods_size(lr_datapaths))) {
> @@ -7484,7 +7554,8 @@ build_lb_affinity_lr_flows(struct lflow_table
*lflows,
>
>      ovn_lflow_add_with_dp_group(
>          lflows, dp_bitmap, ods_size(lr_datapaths),
S_ROUTER_IN_LB_AFF_CHECK,
> -        100, new_lb_match, ds_cstr(&aff_check_action),
&lb->nlb->header_);
> +        100, new_lb_match, ds_cstr(&aff_check_action), &lb->nlb->header_,
> +        lflow_ref);
>
>      /* Prepare common part of affinity LB and affinity learn action. */
>      ds_put_format(&aff_action, "%s = %s; ", reg_vip, lb_vip->vip_str);
> @@ -7566,12 +7637,14 @@ build_lb_affinity_lr_flows(struct lflow_table
*lflows,
>          ovn_lflow_add_with_dp_group(
>              lflows, dp_bitmap, ods_size(lr_datapaths),
>              S_ROUTER_IN_LB_AFF_LEARN, 100, ds_cstr(&aff_match_learn),
> -            ds_cstr(&aff_action_learn), &lb->nlb->header_);
> +            ds_cstr(&aff_action_learn), &lb->nlb->header_,
> +            lflow_ref);
>
>          /* Use already selected backend within affinity timeslot. */
>          ovn_lflow_add_with_dp_group(
>              lflows, dp_bitmap, ods_size(lr_datapaths), S_ROUTER_IN_DNAT,
150,
> -            ds_cstr(&aff_match), ds_cstr(&aff_action),
&lb->nlb->header_);
> +            ds_cstr(&aff_match), ds_cstr(&aff_action), &lb->nlb->header_,
> +            lflow_ref);
>
>          ds_truncate(&aff_action, aff_action_len);
>          ds_truncate(&aff_action_learn, aff_action_learn_len);
> @@ -7631,7 +7704,8 @@ static void
>  build_lb_affinity_ls_flows(struct lflow_table *lflows,
>                             struct ovn_lb_datapaths *lb_dps,
>                             struct ovn_lb_vip *lb_vip,
> -                           const struct ovn_datapaths *ls_datapaths)
> +                           const struct ovn_datapaths *ls_datapaths,
> +                           struct lflow_ref *lflow_ref)
>  {
>      if (!lb_dps->lb->affinity_timeout || !lb_dps->n_nb_ls) {
>          return;
> @@ -7659,7 +7733,7 @@ build_lb_affinity_ls_flows(struct lflow_table
*lflows,
>      ovn_lflow_add_with_dp_group(
>          lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths),
>          S_SWITCH_IN_LB_AFF_CHECK, 100, ds_cstr(&new_lb_match), aff_check,
> -        &lb_dps->lb->nlb->header_);
> +        &lb_dps->lb->nlb->header_, lflow_ref);
>      ds_destroy(&new_lb_match);
>
>      struct ds aff_action = DS_EMPTY_INITIALIZER;
> @@ -7749,13 +7823,14 @@ build_lb_affinity_ls_flows(struct lflow_table
*lflows,
>          ovn_lflow_add_with_dp_group(
>              lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths),
>              S_SWITCH_IN_LB_AFF_LEARN, 100, ds_cstr(&aff_match_learn),
> -            ds_cstr(&aff_action_learn), &lb->nlb->header_);
> +            ds_cstr(&aff_action_learn), &lb->nlb->header_,
> +            lflow_ref);
>
>          /* Use already selected backend within affinity timeslot. */
>          ovn_lflow_add_with_dp_group(
>              lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths),
>              S_SWITCH_IN_LB, 150, ds_cstr(&aff_match),
ds_cstr(&aff_action),
> -            &lb->nlb->header_);
> +            &lb->nlb->header_, lflow_ref);
>
>          ds_truncate(&aff_action, aff_action_len);
>          ds_truncate(&aff_action_learn, aff_action_learn_len);
> @@ -7771,20 +7846,26 @@ build_lb_affinity_ls_flows(struct lflow_table
*lflows,
>
>  static void
>  build_lswitch_lb_affinity_default_flows(struct ovn_datapath *od,
> -                                        struct lflow_table *lflows)
> +                                        struct lflow_table *lflows,
> +                                        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbs);
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_CHECK, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_LEARN, 0, "1", "next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_CHECK, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_LEARN, 0, "1", "next;",
> +                  lflow_ref);
>  }
>
>  static void
>  build_lrouter_lb_affinity_default_flows(struct ovn_datapath *od,
> -                                        struct lflow_table *lflows)
> +                                        struct lflow_table *lflows,
> +                                        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
> -    ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_CHECK, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_LEARN, 0, "1", "next;");
> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_CHECK, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_LEARN, 0, "1", "next;",
> +                  lflow_ref);
>  }
>
>  static void
> @@ -7792,7 +7873,8 @@ build_lb_rules(struct lflow_table *lflows, struct
ovn_lb_datapaths *lb_dps,
>                 const struct ovn_datapaths *ls_datapaths,
>                 const struct chassis_features *features, struct ds *match,
>                 struct ds *action, const struct shash *meter_groups,
> -               const struct hmap *svc_monitor_map)
> +               const struct hmap *svc_monitor_map,
> +               struct lflow_ref *lflow_ref)
>  {
>      const struct ovn_northd_lb *lb = lb_dps->lb;
>      for (size_t i = 0; i < lb->n_vips; i++) {
> @@ -7829,7 +7911,8 @@ build_lb_rules(struct lflow_table *lflows, struct
ovn_lb_datapaths *lb_dps,
>              priority = 120;
>          }
>
> -        build_lb_affinity_ls_flows(lflows, lb_dps, lb_vip, ls_datapaths);
> +        build_lb_affinity_ls_flows(lflows, lb_dps, lb_vip, ls_datapaths,
> +                                   lflow_ref);
>
>          unsigned long *dp_non_meter = NULL;
>          bool build_non_meter = false;
> @@ -7852,14 +7935,16 @@ build_lb_rules(struct lflow_table *lflows, struct
ovn_lb_datapaths *lb_dps,
>                  ovn_lflow_add_with_hint__(
>                          lflows, od, S_SWITCH_IN_LB, priority,
>                          ds_cstr(match), ds_cstr(action),
> -                        NULL, meter, &lb->nlb->header_);
> +                        NULL, meter, &lb->nlb->header_,
> +                        lflow_ref);
>              }
>          }
>          if (!reject || build_non_meter) {
>              ovn_lflow_add_with_dp_group(
>                  lflows, dp_non_meter ? dp_non_meter : lb_dps->nb_ls_map,
>                  ods_size(ls_datapaths), S_SWITCH_IN_LB, priority,
> -                ds_cstr(match), ds_cstr(action), &lb->nlb->header_);
> +                ds_cstr(match), ds_cstr(action), &lb->nlb->header_,
> +                lflow_ref);
>          }
>          bitmap_free(dp_non_meter);
>      }
> @@ -7868,7 +7953,8 @@ build_lb_rules(struct lflow_table *lflows, struct
ovn_lb_datapaths *lb_dps,
>  static void
>  build_stateful(struct ovn_datapath *od,
>                 const struct chassis_features *features,
> -               struct lflow_table *lflows)
> +               struct lflow_table *lflows,
> +               struct lflow_ref *lflow_ref)
>  {
>      const char *ct_block_action = features->ct_no_masked_label
>                                    ? "ct_mark.blocked"
> @@ -7877,9 +7963,11 @@ build_stateful(struct ovn_datapath *od,
>
>      /* Ingress LB, Ingress and Egress stateful Table (Priority 0):
Packets are
>       * allowed by default. */
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_LB, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 0, "1", "next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_LB, 0, "1", "next;",
lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 0, "1", "next;",
> +                  lflow_ref);
>
>      /* If REGBIT_CONNTRACK_COMMIT is set as 1 and
>       * REGBIT_CONNTRACK_SET_LABEL is set to 1, then the packets should be
> @@ -7893,11 +7981,13 @@ build_stateful(struct ovn_datapath *od,
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100,
>                    REGBIT_CONNTRACK_COMMIT" == 1 && "
>                    REGBIT_ACL_LABEL" == 1",
> -                  ds_cstr(&actions));
> +                  ds_cstr(&actions),
> +                  lflow_ref);
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 100,
>                    REGBIT_CONNTRACK_COMMIT" == 1 && "
>                    REGBIT_ACL_LABEL" == 1",
> -                  ds_cstr(&actions));
> +                  ds_cstr(&actions),
> +                  lflow_ref);
>
>      /* If REGBIT_CONNTRACK_COMMIT is set as 1, then the packets should be
>       * committed to conntrack. We always set ct_mark.blocked to 0 here as
> @@ -7908,26 +7998,32 @@ build_stateful(struct ovn_datapath *od,
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100,
>                    REGBIT_CONNTRACK_COMMIT" == 1 && "
>                    REGBIT_ACL_LABEL" == 0",
> -                  ds_cstr(&actions));
> +                  ds_cstr(&actions),
> +                  lflow_ref);
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 100,
>                    REGBIT_CONNTRACK_COMMIT" == 1 && "
>                    REGBIT_ACL_LABEL" == 0",
> -                  ds_cstr(&actions));
> +                  ds_cstr(&actions),
> +                  lflow_ref);
>      ds_destroy(&actions);
>  }
>
>  static void
>  build_lb_hairpin(const struct ls_stateful_record *ls_stateful_rec,
> -                 struct lflow_table *lflows)
> +                 struct lflow_table *lflows,
> +                 struct lflow_ref *lflow_ref)
>  {
>      const struct ovn_datapath *od = ls_stateful_rec->od;
>
>      /* Ingress Pre-Hairpin/Nat-Hairpin/Hairpin tabled (Priority 0).
>       * Packets that don't need hairpinning should continue processing.
>       */
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_NAT_HAIRPIN, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 0, "1", "next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_NAT_HAIRPIN, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 0, "1", "next;",
> +                  lflow_ref);
>
>      if (ls_stateful_rec->has_lb_vip) {
>          /* Check if the packet needs to be hairpinned.
> @@ -7939,7 +8035,8 @@ build_lb_hairpin(const struct ls_stateful_record
*ls_stateful_rec,
>              REGBIT_HAIRPIN " = chk_lb_hairpin(); "
>              REGBIT_HAIRPIN_REPLY " = chk_lb_hairpin_reply(); "
>              "next;",
> -            &od->nbs->header_);
> +            &od->nbs->header_,
> +            lflow_ref);
>
>          /* If packet needs to be hairpinned, snat the src ip with the VIP
>           * for new sessions. */
> @@ -7947,7 +8044,8 @@ build_lb_hairpin(const struct ls_stateful_record
*ls_stateful_rec,
>                                  "ip && ct.new && ct.trk"
>                                  " && "REGBIT_HAIRPIN " == 1",
>                                  "ct_snat_to_vip; next;",
> -                                &od->nbs->header_);
> +                                &od->nbs->header_,
> +                                lflow_ref);
>
>          /* If packet needs to be hairpinned, for established sessions
there
>           * should already be an SNAT conntrack entry.
> @@ -7956,13 +8054,15 @@ build_lb_hairpin(const struct ls_stateful_record
*ls_stateful_rec,
>                                  "ip && ct.est && ct.trk"
>                                  " && "REGBIT_HAIRPIN " == 1",
>                                  "ct_snat;",
> -                                &od->nbs->header_);
> +                                &od->nbs->header_,
> +                                lflow_ref);
>
>          /* For the reply of hairpinned traffic, snat the src ip to the
VIP. */
>          ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_NAT_HAIRPIN, 90,
>                                  "ip && "REGBIT_HAIRPIN_REPLY " == 1",
>                                  "ct_snat;",
> -                                &od->nbs->header_);
> +                                &od->nbs->header_,
> +                                lflow_ref);
>
>          /* Ingress Hairpin table.
>          * - Priority 1: Packets that were SNAT-ed for hairpinning should
be
> @@ -7972,12 +8072,13 @@ build_lb_hairpin(const struct ls_stateful_record
*ls_stateful_rec,
>              lflows, od, S_SWITCH_IN_HAIRPIN, 1,
>              "("REGBIT_HAIRPIN " == 1 || " REGBIT_HAIRPIN_REPLY " == 1)",
>              "eth.dst <-> eth.src; outport = inport; flags.loopback = 1; "
> -            "output;");
> +            "output;", lflow_ref);
>      }
>  }
>
>  static void
> -build_vtep_hairpin(struct ovn_datapath *od, struct lflow_table *lflows)
> +build_vtep_hairpin(struct ovn_datapath *od, struct lflow_table *lflows,
> +                   struct lflow_ref *lflow_ref)
>  {
>      if (!od->has_vtep_lports) {
>          /* There is no need in these flows if datapath has no vtep
lports. */
> @@ -7990,7 +8091,7 @@ build_vtep_hairpin(struct ovn_datapath *od, struct
lflow_table *lflows)
>      char *action = xasprintf("next(pipeline=ingress, table=%d);",
>                               ovn_stage_get_table(S_SWITCH_IN_L2_LKUP));
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 1000,
> -                  REGBIT_FROM_RAMP" == 1", action);
> +                  REGBIT_FROM_RAMP" == 1", action, lflow_ref);
>      free(action);
>
>      /* Ingress pre-arp flow for traffic from VTEP (ramp) switch.
> @@ -8007,7 +8108,7 @@ build_vtep_hairpin(struct ovn_datapath *od, struct
lflow_table *lflows)
>                            REGBIT_FROM_RAMP" == 1 &&
is_chassis_resident(%s)",
>                            op->cr_port->json_key);
>              ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 2000,
> -                          ds_cstr(&match), "next;");
> +                          ds_cstr(&match), "next;", lflow_ref);
>          }
>      }
>
> @@ -8018,14 +8119,15 @@ build_vtep_hairpin(struct ovn_datapath *od,
struct lflow_table *lflows)
>       */
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 65535,
>                    REGBIT_FROM_RAMP" == 1 && (arp || nd_ns)",
> -                  "flags.loopback = 1; next;");
> +                  "flags.loopback = 1; next;", lflow_ref);
>
>      ds_destroy(&match);
>  }
>
>  /* Build logical flows for the forwarding groups */
>  static void
> -build_fwd_group_lflows(struct ovn_datapath *od, struct lflow_table
*lflows)
> +build_fwd_group_lflows(struct ovn_datapath *od, struct lflow_table
*lflows,
> +                       struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbs);
>      if (!od->nbs->n_forwarding_groups) {
> @@ -8060,7 +8162,7 @@ build_fwd_group_lflows(struct ovn_datapath *od,
struct lflow_table *lflows)
>
>          ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 50,
>                                  ds_cstr(&match), ds_cstr(&actions),
> -                                &fwd_group->header_);
> +                                &fwd_group->header_, lflow_ref);
>
>          /* L2 lookup for the forwarding group's virtual MAC */
>          ds_clear(&match);
> @@ -8083,7 +8185,7 @@ build_fwd_group_lflows(struct ovn_datapath *od,
struct lflow_table *lflows)
>          ds_put_format(&actions, "fwd_group(%s);", ds_cstr(&group_ports));
>          ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP, 50,
>                                  ds_cstr(&match), ds_cstr(&actions),
> -                                &fwd_group->header_);
> +                                &fwd_group->header_, lflow_ref);
>      }
>
>      ds_destroy(&match);
> @@ -8231,10 +8333,8 @@ build_lswitch_rport_arp_req_self_orig_flow(struct
ovn_port *op,
>      ds_put_format(&match,
>                    "eth.src == %s && (arp.op == 1 || rarp.op == 3 ||
nd_ns)",
>                    ds_cstr(&eth_src));
> -    ovn_lflow_add_with_lflow_ref(lflows, od, S_SWITCH_IN_L2_LKUP,
priority,
> -                                 ds_cstr(&match),
> -                                 "outport = \""MC_FLOOD_L2"\"; output;",
> -                                 lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, priority,
ds_cstr(&match),
> +                  "outport = \""MC_FLOOD_L2"\"; output;", lflow_ref);
>
>      ds_destroy(&eth_src);
>      ds_destroy(&match);
> @@ -8318,17 +8418,17 @@ build_lswitch_rport_arp_req_flow(const char *ips,
>          ds_put_format(&actions, "clone {outport = %s; output; }; "
>                                  "outport = \""MC_FLOOD_L2"\"; output;",
>                        patch_op->json_key);
> -        ovn_lflow_add_with_lflow_ref_hint(lflows, od,
S_SWITCH_IN_L2_LKUP,
> -                                          priority, ds_cstr(&match),
> -                                          ds_cstr(&actions), stage_hint,
> -                                          lflow_ref);
> +        ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP,
> +                                priority, ds_cstr(&match),
> +                                ds_cstr(&actions), stage_hint,
> +                                lflow_ref);
>      } else {
>          ds_put_format(&actions, "outport = %s; output;",
patch_op->json_key);
> -        ovn_lflow_add_with_lflow_ref_hint(lflows, od,
S_SWITCH_IN_L2_LKUP,
> -                                          priority, ds_cstr(&match),
> -                                          ds_cstr(&actions),
> -                                          stage_hint,
> -                                          lflow_ref);
> +        ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP,
> +                                priority, ds_cstr(&match),
> +                                ds_cstr(&actions),
> +                                stage_hint,
> +                                lflow_ref);
>      }
>
>      ds_destroy(&match);
> @@ -8484,7 +8584,8 @@ build_dhcpv4_options_flows(struct ovn_port *op,
>                             struct lport_addresses *lsp_addrs,
>                             struct ovn_port *inport, bool is_external,
>                             const struct shash *meter_groups,
> -                           struct lflow_table *lflows)
> +                           struct lflow_table *lflows,
> +                           struct lflow_ref *lflow_ref)
>  {
>      struct ds match = DS_EMPTY_INITIALIZER;
>
> @@ -8515,7 +8616,7 @@ build_dhcpv4_options_flows(struct ovn_port *op,
>                                op->json_key);
>              }
>
> -            ovn_lflow_add_with_lflow_ref_hint__(lflows, op->od,
> +            ovn_lflow_add_with_hint__(lflows, op->od,
>                                        S_SWITCH_IN_DHCP_OPTIONS, 100,
>                                        ds_cstr(&match),
>                                        ds_cstr(&options_action),
> @@ -8524,7 +8625,7 @@ build_dhcpv4_options_flows(struct ovn_port *op,
>                                                       op->od->nbs->copp,
>                                                       meter_groups),
>                                        &op->nbsp->dhcpv4_options->header_,
> -                                      op->lflow_ref);
> +                                      lflow_ref);
>              ds_clear(&match);
>
>              /* If REGBIT_DHCP_OPTS_RESULT is set, it means the
> @@ -8544,7 +8645,7 @@ build_dhcpv4_options_flows(struct ovn_port *op,
>                  lflows, op->od, S_SWITCH_IN_DHCP_RESPONSE, 100,
>                  ds_cstr(&match), ds_cstr(&response_action), inport->key,
>                  &op->nbsp->dhcpv4_options->header_,
> -                op->lflow_ref);
> +                lflow_ref);
>              ds_destroy(&options_action);
>              ds_destroy(&response_action);
>              ds_destroy(&ipv4_addr_match);
> @@ -8572,7 +8673,7 @@ build_dhcpv4_options_flows(struct ovn_port *op,
>                      lflows, op->od, S_SWITCH_OUT_ACL_EVAL, 34000,
>                      ds_cstr(&match),dhcp_actions, op->key,
>                      &op->nbsp->dhcpv4_options->header_,
> -                    op->lflow_ref);
> +                    lflow_ref);
>              }
>              break;
>          }
> @@ -8585,7 +8686,8 @@ build_dhcpv6_options_flows(struct ovn_port *op,
>                             struct lport_addresses *lsp_addrs,
>                             struct ovn_port *inport, bool is_external,
>                             const struct shash *meter_groups,
> -                           struct lflow_table *lflows)
> +                           struct lflow_table *lflows,
> +                           struct lflow_ref *lflow_ref)
>  {
>      struct ds match = DS_EMPTY_INITIALIZER;
>
> @@ -8607,7 +8709,7 @@ build_dhcpv6_options_flows(struct ovn_port *op,
>                                op->json_key);
>              }
>
> -            ovn_lflow_add_with_lflow_ref_hint__(lflows, op->od,
> +            ovn_lflow_add_with_hint__(lflows, op->od,
>                                        S_SWITCH_IN_DHCP_OPTIONS, 100,
>                                        ds_cstr(&match),
>                                        ds_cstr(&options_action),
> @@ -8616,7 +8718,7 @@ build_dhcpv6_options_flows(struct ovn_port *op,
>                                                       op->od->nbs->copp,
>                                                       meter_groups),
>                                        &op->nbsp->dhcpv6_options->header_,
> -                                      op->lflow_ref);
> +                                      lflow_ref);
>
>              /* If REGBIT_DHCP_OPTS_RESULT is set to 1, it means the
>               * put_dhcpv6_opts action is successful */
> @@ -8624,7 +8726,7 @@ build_dhcpv6_options_flows(struct ovn_port *op,
>              ovn_lflow_add_with_lport_and_hint(
>                  lflows, op->od, S_SWITCH_IN_DHCP_RESPONSE, 100,
>                  ds_cstr(&match), ds_cstr(&response_action), inport->key,
> -                &op->nbsp->dhcpv6_options->header_, op->lflow_ref);
> +                &op->nbsp->dhcpv6_options->header_, lflow_ref);
>              ds_destroy(&options_action);
>              ds_destroy(&response_action);
>
> @@ -8657,7 +8759,7 @@ build_dhcpv6_options_flows(struct ovn_port *op,
>                      lflows, op->od, S_SWITCH_OUT_ACL_EVAL, 34000,
>                      ds_cstr(&match),dhcp6_actions, op->key,
>                      &op->nbsp->dhcpv6_options->header_,
> -                    op->lflow_ref);
> +                    lflow_ref);
>              }
>              break;
>          }
> @@ -8668,7 +8770,8 @@ build_dhcpv6_options_flows(struct ovn_port *op,
>  static void
>  build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op,
>                                                   const struct ovn_port
*port,
> -                                                 struct lflow_table
*lflows)
> +                                                 struct lflow_table
*lflows,
> +                                                 struct lflow_ref
*lflow_ref)
>  {
>      struct ds match = DS_EMPTY_INITIALIZER;
>
> @@ -8688,7 +8791,7 @@
build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op,
>                      ovn_lflow_add_with_lport_and_hint(
>                          lflows, op->od, S_SWITCH_IN_EXTERNAL_PORT, 100,
>                          ds_cstr(&match),  debug_drop_action(), port->key,
> -                        &op->nbsp->header_, op->lflow_ref);
> +                        &op->nbsp->header_, lflow_ref);
>                  }
>                  for (size_t l = 0; l < rp->lsp_addrs[k].n_ipv6_addrs;
l++) {
>                      ds_clear(&match);
> @@ -8704,7 +8807,7 @@
build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op,
>                      ovn_lflow_add_with_lport_and_hint(
>                          lflows, op->od, S_SWITCH_IN_EXTERNAL_PORT, 100,
>                          ds_cstr(&match), debug_drop_action(), port->key,
> -                        &op->nbsp->header_, op->lflow_ref);
> +                        &op->nbsp->header_, lflow_ref);
>                  }
>
>                  ds_clear(&match);
> @@ -8721,7 +8824,7 @@
build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op,
>                                                    debug_drop_action(),
>                                                    port->key,
>                                                    &op->nbsp->header_,
> -                                                  op->lflow_ref);
> +                                                  lflow_ref);
>              }
>          }
>      }
> @@ -8736,19 +8839,22 @@ is_vlan_transparent(const struct ovn_datapath *od)
>
>  static void
>  build_lswitch_lflows_l2_unknown(struct ovn_datapath *od,
> -                                struct lflow_table *lflows)
> +                                struct lflow_table *lflows,
> +                                struct lflow_ref *lflow_ref)
>  {
>      /* Ingress table 25/26: Destination lookup for unknown MACs. */
>      if (od->has_unknown) {
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 50,
>                        "outport == \"none\"",
> -                      "outport = \""MC_UNKNOWN "\"; output;");
> +                      "outport = \""MC_UNKNOWN "\"; output;",
> +                      lflow_ref);
>      } else {
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 50,
> -                      "outport == \"none\"",  debug_drop_action());
> +                      "outport == \"none\"",  debug_drop_action(),
> +                      lflow_ref);
>      }
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 0, "1",
> -                  "output;");
> +                  "output;", lflow_ref);
>  }
>
>  /* Build pre-ACL and ACL tables for both ingress and egress.
> @@ -8758,42 +8864,49 @@ build_lswitch_lflows_pre_acl_and_acl(
>      struct ovn_datapath *od,
>      const struct chassis_features *features,
>      struct lflow_table *lflows,
> -    const struct shash *meter_groups)
> +    const struct shash *meter_groups,
> +    struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbs);
> -    build_pre_acls(od, lflows);
> -    build_pre_lb(od, meter_groups, lflows);
> -    build_pre_stateful(od, features, lflows);
> -    build_qos(od, lflows);
> -    build_stateful(od, features, lflows);
> -    build_vtep_hairpin(od, lflows);
> +    build_pre_acls(od, lflows, lflow_ref);
> +    build_pre_lb(od, meter_groups, lflows, lflow_ref);
> +    build_pre_stateful(od, features, lflows, lflow_ref);
> +    build_qos(od, lflows, lflow_ref);
> +    build_stateful(od, features, lflows, lflow_ref);
> +    build_vtep_hairpin(od, lflows, lflow_ref);
>  }
>
>  /* Logical switch ingress table 0: Admission control framework (priority
>   * 100). */
>  static void
>  build_lswitch_lflows_admission_control(struct ovn_datapath *od,
> -                                       struct lflow_table *lflows)
> +                                       struct lflow_table *lflows,
> +                                       struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbs);
>      /* Logical VLANs not supported. */
>      if (!is_vlan_transparent(od)) {
>          /* Block logical VLANs. */
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 100,
> -                      "vlan.present", debug_drop_action());
> +                      "vlan.present", debug_drop_action(),
> +                      lflow_ref);
>      }
>
>      /* Broadcast/multicast source address is invalid. */
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 100,
> -                  "eth.src[40]", debug_drop_action());
> +                  "eth.src[40]", debug_drop_action(),
> +                  lflow_ref);
>
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 50, "1",
> -                  REGBIT_PORT_SEC_DROP" = check_in_port_sec(); next;");
> +                  REGBIT_PORT_SEC_DROP" = check_in_port_sec(); next;",
> +                  lflow_ref);
>
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 50,
> -                  REGBIT_PORT_SEC_DROP" == 1", debug_drop_action());
> +                  REGBIT_PORT_SEC_DROP" == 1", debug_drop_action(),
> +                  lflow_ref);
>
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 0, "1",
"next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 0, "1",
"next;",
> +                  lflow_ref);
>  }
>
>  /* Ingress table 19: ARP/ND responder, skip requests coming from localnet
> @@ -8950,12 +9063,12 @@ build_lswitch_arp_nd_responder_known_ips(struct
ovn_port *op,
>                      "output;",
>                      op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s,
>                      op->lsp_addrs[i].ipv4_addrs[j].addr_s);
> -                ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
> -
 S_SWITCH_IN_ARP_ND_RSP, 50,
> -                                                  ds_cstr(match),
> -                                                  ds_cstr(actions),
> -                                                  &op->nbsp->header_,
> -                                                  op->lflow_ref);
> +                ovn_lflow_add_with_hint(lflows, op->od,
> +                                        S_SWITCH_IN_ARP_ND_RSP, 50,
> +                                        ds_cstr(match),
> +                                        ds_cstr(actions),
> +                                        &op->nbsp->header_,
> +                                        op->lflow_ref);
>
>                  /* Do not reply to an ARP request from the port that owns
>                   * the address (otherwise a DHCP client that ARPs to
check
> @@ -9005,16 +9118,16 @@ build_lswitch_arp_nd_responder_known_ips(struct
ovn_port *op,
>                          op->lsp_addrs[i].ipv6_addrs[j].addr_s,
>                          op->lsp_addrs[i].ipv6_addrs[j].addr_s,
>                          op->lsp_addrs[i].ea_s);
> -                ovn_lflow_add_with_lflow_ref_hint__(lflows, op->od,
> -
 S_SWITCH_IN_ARP_ND_RSP, 50,
> -                                                    ds_cstr(match),
> -                                                    ds_cstr(actions),
> -                                                    NULL,
> -
 copp_meter_get(COPP_ND_NA,
> -
 op->od->nbs->copp,
> -                                                        meter_groups),
> -                                                    &op->nbsp->header_,
> -                                                    op->lflow_ref);
> +                ovn_lflow_add_with_hint__(lflows, op->od,
> +                                          S_SWITCH_IN_ARP_ND_RSP, 50,
> +                                          ds_cstr(match),
> +                                          ds_cstr(actions),
> +                                          NULL,
> +                                          copp_meter_get(COPP_ND_NA,
> +                                            op->od->nbs->copp,
> +                                            meter_groups),
> +                                          &op->nbsp->header_,
> +                                          op->lflow_ref);
>
>                  /* Do not reply to a solicitation from the port that owns
>                   * the address (otherwise DAD detection will fail). */
> @@ -9070,12 +9183,12 @@ build_lswitch_arp_nd_responder_known_ips(struct
ovn_port *op,
>                  ea_s,
>                  ea_s);
>
> -            ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
> -                                              S_SWITCH_IN_ARP_ND_RSP,
> -                                              30, ds_cstr(match),
> -                                              ds_cstr(actions),
> -                                              &op->nbsp->header_,
> -                                              op->lflow_ref);
> +            ovn_lflow_add_with_hint(lflows, op->od,
> +                                    S_SWITCH_IN_ARP_ND_RSP,
> +                                    30, ds_cstr(match),
> +                                    ds_cstr(actions),
> +                                    &op->nbsp->header_,
> +                                    op->lflow_ref);
>          }
>
>          /* Add IPv6 NDP responses.
> @@ -9118,16 +9231,16 @@ build_lswitch_arp_nd_responder_known_ips(struct
ovn_port *op,
>                      lsp_is_router(op->nbsp) ? "nd_na_router" : "nd_na",
>                      ea_s,
>                      ea_s);
> -            ovn_lflow_add_with_lflow_ref_hint__(lflows, op->od,
> -                                                S_SWITCH_IN_ARP_ND_RSP,
30,
> -                                                ds_cstr(match),
> -                                                ds_cstr(actions),
> -                                                NULL,
> -
 copp_meter_get(COPP_ND_NA,
> -                                                    op->od->nbs->copp,
> -                                                    meter_groups),
> -                                                &op->nbsp->header_,
> -                                                op->lflow_ref);
> +            ovn_lflow_add_with_hint__(lflows, op->od,
> +                                      S_SWITCH_IN_ARP_ND_RSP, 30,
> +                                      ds_cstr(match),
> +                                      ds_cstr(actions),
> +                                      NULL,
> +                                      copp_meter_get(COPP_ND_NA,
> +                                        op->od->nbs->copp,
> +                                        meter_groups),
> +                                      &op->nbsp->header_,
> +                                      op->lflow_ref);
>              ds_destroy(&ip6_dst_match);
>              ds_destroy(&nd_target_match);
>          }
> @@ -9138,10 +9251,12 @@ build_lswitch_arp_nd_responder_known_ips(struct
ovn_port *op,
>   * (priority 0)*/
>  static void
>  build_lswitch_arp_nd_responder_default(struct ovn_datapath *od,
> -                                       struct lflow_table *lflows)
> +                                       struct lflow_table *lflows,
> +                                       struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbs);
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 0, "1", "next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 0, "1", "next;",
> +                  lflow_ref);
>  }
>
>  /* Ingress table 19: ARP/ND responder for service monitor source ip.
> @@ -9151,7 +9266,8 @@ build_lswitch_arp_nd_service_monitor(const struct
ovn_northd_lb *lb,
>                                       const struct hmap *ls_ports,
>                                       struct lflow_table *lflows,
>                                       struct ds *actions,
> -                                     struct ds *match)
> +                                     struct ds *match,
> +                                     struct lflow_ref *lflow_ref)
>  {
>      for (size_t i = 0; i < lb->n_vips; i++) {
>          struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[i];
> @@ -9215,7 +9331,8 @@ build_lswitch_arp_nd_service_monitor(const struct
ovn_northd_lb *lb,
>                                      op->od,
>                                      S_SWITCH_IN_ARP_ND_RSP, 110,
>                                      ds_cstr(match), ds_cstr(actions),
> -                                    &lb->nlb->header_);
> +                                    &lb->nlb->header_,
> +                                    lflow_ref);
>          }
>      }
>  }
> @@ -9255,19 +9372,19 @@ build_lswitch_dhcp_options_and_response(struct
ovn_port *op,
>                  build_dhcpv4_options_flows(
>                      op, &op->lsp_addrs[i],
>                      op->od->localnet_ports[j], is_external,
> -                    meter_groups, lflows);
> +                    meter_groups, lflows, op->lflow_ref);
>                  build_dhcpv6_options_flows(
>                      op, &op->lsp_addrs[i],
>                      op->od->localnet_ports[j], is_external,
> -                    meter_groups, lflows);
> +                    meter_groups, lflows, op->lflow_ref);
>              }
>          } else {
>              build_dhcpv4_options_flows(op, &op->lsp_addrs[i], op,
>                                         is_external, meter_groups,
> -                                       lflows);
> +                                       lflows, op->lflow_ref);
>              build_dhcpv6_options_flows(op, &op->lsp_addrs[i], op,
>                                         is_external, meter_groups,
> -                                       lflows);
> +                                       lflows, op->lflow_ref);
>          }
>      }
>  }
> @@ -9280,14 +9397,20 @@ build_lswitch_dhcp_options_and_response(struct
ovn_port *op,
>   * (priority 0). */
>  static void
>  build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od,
> -                                        struct lflow_table *lflows)
> +                                    struct lflow_table *lflows,
> +                                    struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbs);
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_OPTIONS, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_RESPONSE, 0, "1",
"next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_EXTERNAL_PORT, 0, "1",
"next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_OPTIONS, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_RESPONSE, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_EXTERNAL_PORT, 0, "1", "next;",
> +                  lflow_ref);
>  }
>
>  /* Logical switch ingress table 22 and 23: DNS lookup and response
> @@ -9296,7 +9419,8 @@ build_lswitch_dhcp_and_dns_defaults(struct
ovn_datapath *od,
>  static void
>  build_lswitch_dns_lookup_and_response(struct ovn_datapath *od,
>                                        struct lflow_table *lflows,
> -                                      const struct shash *meter_groups)
> +                                      const struct shash *meter_groups,
> +                                      struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbs);
>      if (!ls_has_dns_records(od->nbs)) {
> @@ -9306,18 +9430,18 @@ build_lswitch_dns_lookup_and_response(struct
ovn_datapath *od,
>                        "udp.dst == 53",
>                        REGBIT_DNS_LOOKUP_RESULT" = dns_lookup(); next;",
>                        copp_meter_get(COPP_DNS, od->nbs->copp,
> -                                     meter_groups));
> +                                     meter_groups), lflow_ref);
>      const char *dns_action = "eth.dst <-> eth.src; ip4.src <-> ip4.dst; "
>                    "udp.dst = udp.src; udp.src = 53; outport = inport; "
>                    "flags.loopback = 1; output;";
>      const char *dns_match = "udp.dst == 53 && "REGBIT_DNS_LOOKUP_RESULT;
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 100,
> -                  dns_match, dns_action);
> +                  dns_match, dns_action, lflow_ref);
>      dns_action = "eth.dst <-> eth.src; ip6.src <-> ip6.dst; "
>                    "udp.dst = udp.src; udp.src = 53; outport = inport; "
>                    "flags.loopback = 1; output;";
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 100,
> -                  dns_match, dns_action);
> +                  dns_match, dns_action, lflow_ref);
>  }
>
>  /* Table 24: External port. Drop ARP request for router ips from
> @@ -9334,7 +9458,8 @@ build_lswitch_external_port(struct ovn_port *op,
>      }
>      for (size_t i = 0; i < op->od->n_localnet_ports; i++) {
>          build_drop_arp_nd_flows_for_unbound_router_ports(
> -            op, op->od->localnet_ports[i], lflows);
> +            op, op->od->localnet_ports[i], lflows,
> +            op->lflow_ref);
>      }
>  }
>
> @@ -9344,7 +9469,8 @@ static void
>  build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
>                                          struct lflow_table *lflows,
>                                          struct ds *actions,
> -                                        const struct shash *meter_groups)
> +                                        const struct shash *meter_groups,
> +                                        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbs);
>
> @@ -9352,7 +9478,7 @@ build_lswitch_destination_lookup_bmcast(struct
ovn_datapath *od,
>                        "eth.dst == $svc_monitor_mac && (tcp || icmp ||
icmp6)",
>                        "handle_svc_check(inport);",
>                        copp_meter_get(COPP_SVC_MONITOR, od->nbs->copp,
> -                                     meter_groups));
> +                                     meter_groups), lflow_ref);
>
>      struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw;
>
> @@ -9363,27 +9489,31 @@ build_lswitch_destination_lookup_bmcast(struct
ovn_datapath *od,
>          ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
>                            "igmp", ds_cstr(actions),
>                            copp_meter_get(COPP_IGMP, od->nbs->copp,
> -                                         meter_groups));
> +                                         meter_groups),
> +                          lflow_ref);
>
>          /* Punt MLD traffic to controller. */
>          ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
>                            "mldv1 || mldv2", ds_cstr(actions),
>                            copp_meter_get(COPP_IGMP, od->nbs->copp,
> -                                         meter_groups));
> +                                         meter_groups),
> +                          lflow_ref);
>
>          /* Flood all IP multicast traffic destined to 224.0.0.X to all
>           * ports - RFC 4541, section 2.1.2, item 2.
>           */
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 85,
>                        "ip4.mcast && ip4.dst == 224.0.0.0/24",
> -                      "outport = \""MC_FLOOD_L2"\"; output;");
> +                      "outport = \""MC_FLOOD_L2"\"; output;",
> +                      lflow_ref);
>
>          /* Flood all IPv6 multicast traffic destined to reserved
>           * multicast IPs (RFC 4291, 2.7.1).
>           */
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 85,
>                        "ip6.mcast_flood",
> -                      "outport = \""MC_FLOOD"\"; output;");
> +                      "outport = \""MC_FLOOD"\"; output;",
> +                      lflow_ref);
>
>          /* Forward uregistered IP multicast to routers with relay enabled
>           * and to any ports configured to flood IP multicast traffic.
> @@ -9415,7 +9545,7 @@ build_lswitch_destination_lookup_bmcast(struct
ovn_datapath *od,
>
>              ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80,
>                            "ip4.mcast || ip6.mcast",
> -                          ds_cstr(actions));
> +                          ds_cstr(actions), lflow_ref);
>          }
>      }
>
> @@ -9423,11 +9553,12 @@ build_lswitch_destination_lookup_bmcast(struct
ovn_datapath *od,
>                         "broadcast-arps-to-all-routers", true)) {
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 72,
>                        "eth.mcast && (arp.op == 1 || nd_ns)",
> -                      "outport = \""MC_FLOOD_L2"\"; output;");
> +                      "outport = \""MC_FLOOD_L2"\"; output;",
> +                      lflow_ref);
>      }
>
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 70, "eth.mcast",
> -                  "outport = \""MC_FLOOD"\"; output;");
> +                  "outport = \""MC_FLOOD"\"; output;", lflow_ref);
>  }
>
>
> @@ -9437,7 +9568,8 @@ static void
>  build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group,
>                                  struct lflow_table *lflows,
>                                  struct ds *actions,
> -                                struct ds *match)
> +                                struct ds *match,
> +                                struct lflow_ref *lflow_ref)
>  {
>      uint64_t dummy;
>
> @@ -9509,7 +9641,7 @@ build_lswitch_ip_mcast_igmp_mld(struct
ovn_igmp_group *igmp_group,
>                        igmp_group->mcgroup.name);
>
>          ovn_lflow_add(lflows, igmp_group->datapath, S_SWITCH_IN_L2_LKUP,
> -                      90, ds_cstr(match), ds_cstr(actions));
> +                      90, ds_cstr(match), ds_cstr(actions), lflow_ref);
>      }
>  }
>
> @@ -9549,12 +9681,12 @@ build_lswitch_ip_unicast_lookup(struct ovn_port
*op,
>
>              ds_clear(actions);
>              ds_put_format(actions, action, op->json_key);
> -            ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
> -                                              S_SWITCH_IN_L2_LKUP,
> -                                              50, ds_cstr(match),
> -                                              ds_cstr(actions),
> -                                              &op->nbsp->header_,
> -                                              op->lflow_ref);
> +            ovn_lflow_add_with_hint(lflows, op->od,
> +                                    S_SWITCH_IN_L2_LKUP,
> +                                    50, ds_cstr(match),
> +                                    ds_cstr(actions),
> +                                    &op->nbsp->header_,
> +                                    op->lflow_ref);
>          } else if (!strcmp(op->nbsp->addresses[i], "unknown")) {
>              continue;
>          } else if (is_dynamic_lsp_address(op->nbsp->addresses[i])) {
> @@ -9569,12 +9701,12 @@ build_lswitch_ip_unicast_lookup(struct ovn_port
*op,
>
>              ds_clear(actions);
>              ds_put_format(actions, action, op->json_key);
> -            ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
> -                                              S_SWITCH_IN_L2_LKUP,
> -                                              50, ds_cstr(match),
> -                                              ds_cstr(actions),
> -                                              &op->nbsp->header_,
> -                                              op->lflow_ref);
> +            ovn_lflow_add_with_hint(lflows, op->od,
> +                                    S_SWITCH_IN_L2_LKUP,
> +                                    50, ds_cstr(match),
> +                                    ds_cstr(actions),
> +                                    &op->nbsp->header_,
> +                                    op->lflow_ref);
>          } else if (!strcmp(op->nbsp->addresses[i], "router")) {
>              if (!op->peer || !op->peer->nbrp
>                  || !ovs_scan(op->peer->nbrp->mac,
> @@ -9626,11 +9758,11 @@ build_lswitch_ip_unicast_lookup(struct ovn_port
*op,
>
>              ds_clear(actions);
>              ds_put_format(actions, action, op->json_key);
> -            ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
> -                                              S_SWITCH_IN_L2_LKUP, 50,
> -                                              ds_cstr(match),
ds_cstr(actions),
> -                                              &op->nbsp->header_,
> -                                              op->lflow_ref);
> +            ovn_lflow_add_with_hint(lflows, op->od,
> +                                    S_SWITCH_IN_L2_LKUP, 50,
> +                                    ds_cstr(match), ds_cstr(actions),
> +                                    &op->nbsp->header_,
> +                                    op->lflow_ref);
>          } else {
>              static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1,
1);
>
> @@ -9678,7 +9810,7 @@ build_lswitch_ip_unicast_lookup_for_nats(struct
ovn_port *op,
>
>              ds_clear(actions);
>              ds_put_format(actions, action, op->json_key);
> -            ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
> +            ovn_lflow_add_with_hint(lflows, op->od,
>                                      S_SWITCH_IN_L2_LKUP, 50,
>                                      ds_cstr(match),
>                                      ds_cstr(actions),
> @@ -9926,7 +10058,8 @@ static void
>  build_routing_policy_flow(struct lflow_table *lflows, struct
ovn_datapath *od,
>                            const struct hmap *lr_ports,
>                            const struct nbrec_logical_router_policy *rule,
> -                          const struct ovsdb_idl_row *stage_hint)
> +                          const struct ovsdb_idl_row *stage_hint,
> +                          struct lflow_ref *lflow_ref)
>  {
>      struct ds match = DS_EMPTY_INITIALIZER;
>      struct ds actions = DS_EMPTY_INITIALIZER;
> @@ -9982,7 +10115,8 @@ build_routing_policy_flow(struct lflow_table
*lflows, struct ovn_datapath *od,
>      ds_put_format(&match, "%s", rule->match);
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY,
rule->priority,
> -                            ds_cstr(&match), ds_cstr(&actions),
stage_hint);
> +                            ds_cstr(&match), ds_cstr(&actions),
stage_hint,
> +                            lflow_ref);
>      ds_destroy(&match);
>      ds_destroy(&actions);
>  }
> @@ -9992,7 +10126,8 @@ build_ecmp_routing_policy_flows(struct lflow_table
*lflows,
>                                  struct ovn_datapath *od,
>                                  const struct hmap *lr_ports,
>                                  const struct nbrec_logical_router_policy
*rule,
> -                                uint16_t ecmp_group_id)
> +                                uint16_t ecmp_group_id,
> +                                struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(rule->n_nexthops > 1);
>
> @@ -10064,7 +10199,8 @@ build_ecmp_routing_policy_flows(struct
lflow_table *lflows,
>                        ecmp_group_id, i + 1);
>          ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY_ECMP,
>                                  100, ds_cstr(&match),
> -                                ds_cstr(&actions), &rule->header_);
> +                                ds_cstr(&actions), &rule->header_,
> +                                lflow_ref);
>      }
>
>      ds_clear(&actions);
> @@ -10082,7 +10218,8 @@ build_ecmp_routing_policy_flows(struct
lflow_table *lflows,
>      ds_put_cstr(&actions, ");");
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY,
>                              rule->priority, rule->match,
> -                            ds_cstr(&actions), &rule->header_);
> +                            ds_cstr(&actions), &rule->header_,
> +                            lflow_ref);
>
>  cleanup:
>      ds_destroy(&match);
> @@ -10127,7 +10264,8 @@ get_route_table_id(struct simap *route_tables,
const char *route_table_name)
>  static void
>  build_route_table_lflow(struct ovn_datapath *od, struct lflow_table
*lflows,
>                          struct nbrec_logical_router_port *lrp,
> -                        struct simap *route_tables)
> +                        struct simap *route_tables,
> +                        struct lflow_ref *lflow_ref)
>  {
>      struct ds match = DS_EMPTY_INITIALIZER;
>      struct ds actions = DS_EMPTY_INITIALIZER;
> @@ -10143,7 +10281,7 @@ build_route_table_lflow(struct ovn_datapath *od,
struct lflow_table *lflows,
>                    REG_ROUTE_TABLE_ID, rtb_id);
>
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_PRE, 100,
> -                  ds_cstr(&match), ds_cstr(&actions));
> +                  ds_cstr(&match), ds_cstr(&actions), lflow_ref);
>
>      ds_destroy(&match);
>      ds_destroy(&actions);
> @@ -10542,7 +10680,8 @@ add_ecmp_symmetric_reply_flows(struct lflow_table
*lflows,
>                                 const char *port_ip,
>                                 struct ovn_port *out_port,
>                                 const struct parsed_route *route,
> -                               struct ds *route_match)
> +                               struct ds *route_match,
> +                               struct lflow_ref *lflow_ref)
>  {
>      const struct nbrec_logical_router_static_route *st_route =
route->route;
>      struct ds base_match = DS_EMPTY_INITIALIZER;
> @@ -10565,12 +10704,12 @@ add_ecmp_symmetric_reply_flows(struct
lflow_table *lflows,
>      free(cidr);
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, 100,
>                               ds_cstr(&base_match), "ct_next;",
> -                             &st_route->header_);
> +                             &st_route->header_, lflow_ref);
>
>      /* And packets that go out over an ECMP route need conntrack */
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, 100,
>                               ds_cstr(route_match), "ct_next;",
> -                             &st_route->header_);
> +                             &st_route->header_, lflow_ref);
>
>      /* Save src eth and inport in ct_label for packets that arrive over
>       * an ECMP route.
> @@ -10587,7 +10726,8 @@ add_ecmp_symmetric_reply_flows(struct lflow_table
*lflows,
>              ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
>                              ds_cstr(&match), ds_cstr(&actions),
> -                            &st_route->header_);
> +                            &st_route->header_,
> +                            lflow_ref);
>      ds_clear(&match);
>      ds_put_format(&match, "%s && (ct.new && !ct.est) && udp",
>                    ds_cstr(&base_match));
> @@ -10599,7 +10739,8 @@ add_ecmp_symmetric_reply_flows(struct lflow_table
*lflows,
>              ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
>                              ds_cstr(&match), ds_cstr(&actions),
> -                            &st_route->header_);
> +                            &st_route->header_,
> +                            lflow_ref);
>      ds_clear(&match);
>      ds_put_format(&match, "%s && (ct.new && !ct.est) && sctp",
>                    ds_cstr(&base_match));
> @@ -10611,7 +10752,8 @@ add_ecmp_symmetric_reply_flows(struct lflow_table
*lflows,
>              ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
>                              ds_cstr(&match), ds_cstr(&actions),
> -                            &st_route->header_);
> +                            &st_route->header_,
> +                            lflow_ref);
>
>      ds_clear(&match);
>      ds_put_format(&match,
> @@ -10625,7 +10767,8 @@ add_ecmp_symmetric_reply_flows(struct lflow_table
*lflows,
>              ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
>                              ds_cstr(&match), ds_cstr(&actions),
> -                            &st_route->header_);
> +                            &st_route->header_,
> +                            lflow_ref);
>
>      ds_clear(&match);
>      ds_put_format(&match,
> @@ -10639,7 +10782,8 @@ add_ecmp_symmetric_reply_flows(struct lflow_table
*lflows,
>              ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
>                              ds_cstr(&match), ds_cstr(&actions),
> -                            &st_route->header_);
> +                            &st_route->header_,
> +                            lflow_ref);
>      ds_clear(&match);
>      ds_put_format(&match,
>              "%s && (!ct.rpl && ct.est) && sctp",
> @@ -10652,7 +10796,8 @@ add_ecmp_symmetric_reply_flows(struct lflow_table
*lflows,
>              ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
>                              ds_cstr(&match), ds_cstr(&actions),
> -                            &st_route->header_);
> +                            &st_route->header_,
> +                            lflow_ref);
>
>      /* Bypass ECMP selection if we already have ct_label information
>       * for where to route the packet.
> @@ -10671,12 +10816,14 @@ add_ecmp_symmetric_reply_flows(struct
lflow_table *lflows,
>                    port_ip, out_port->json_key);
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING, 10300,
>                             ds_cstr(&match), ds_cstr(&actions),
> -                           &st_route->header_);
> +                           &st_route->header_,
> +                           lflow_ref);
>
>      /* Egress reply traffic for symmetric ECMP routes skips router
policies. */
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY, 65535,
>                              ds_cstr(&ecmp_reply), "next;",
> -                            &st_route->header_);
> +                            &st_route->header_,
> +                            lflow_ref);
>
>      /* Use REG_ECMP_ETH_FULL to pass the eth field from ct_label to
eth.dst to
>       * avoid masked access to ct_label. Otherwise it may prevent OVS flow
> @@ -10692,7 +10839,8 @@ add_ecmp_symmetric_reply_flows(struct lflow_table
*lflows,
>                           " pop(" REG_ECMP_ETH_FULL "); next;";
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ARP_RESOLVE,
>                              200, ds_cstr(&ecmp_reply),
> -                            action, &st_route->header_);
> +                            action, &st_route->header_,
> +                            lflow_ref);
>
>      ds_destroy(&base_match);
>      ds_destroy(&match);
> @@ -10703,7 +10851,8 @@ add_ecmp_symmetric_reply_flows(struct lflow_table
*lflows,
>  static void
>  build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath
*od,
>                        bool ct_masked_mark, const struct hmap *lr_ports,
> -                      struct ecmp_groups_node *eg)
> +                      struct ecmp_groups_node *eg,
> +                      struct lflow_ref *lflow_ref)
>
>  {
>      bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&eg->prefix);
> @@ -10736,7 +10885,8 @@ build_ecmp_route_flow(struct lflow_table *lflows,
struct ovn_datapath *od,
>      ds_put_cstr(&actions, ");");
>
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, priority,
> -                  ds_cstr(&route_match), ds_cstr(&actions));
> +                  ds_cstr(&route_match), ds_cstr(&actions),
> +                  lflow_ref);
>
>      /* Add per member flow */
>      struct ds match = DS_EMPTY_INITIALIZER;
> @@ -10759,7 +10909,8 @@ build_ecmp_route_flow(struct lflow_table *lflows,
struct ovn_datapath *od,
>                                                       out_port->key)) {
>              add_ecmp_symmetric_reply_flows(lflows, od, ct_masked_mark,
>                                             lrp_addr_s, out_port,
> -                                           route_, &route_match);
> +                                           route_, &route_match,
> +                                           lflow_ref);
>          }
>          ds_clear(&match);
>          ds_put_format(&match, REG_ECMP_GROUP_ID" == %"PRIu16" && "
> @@ -10779,7 +10930,7 @@ build_ecmp_route_flow(struct lflow_table *lflows,
struct ovn_datapath *od,
>                        out_port->json_key);
>          ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP,
100,
>                                  ds_cstr(&match), ds_cstr(&actions),
> -                                &route->header_);
> +                                &route->header_, lflow_ref);
>      }
>      sset_destroy(&visited_ports);
>      ds_destroy(&match);
> @@ -10836,17 +10987,17 @@ add_route(struct lflow_table *lflows, struct
ovn_datapath *od,
>          ds_put_format(&actions, "ip.ttl--; %s",
ds_cstr(&common_actions));
>      }
>
> -    ovn_lflow_add_with_lflow_ref_hint(lflows, od, S_ROUTER_IN_IP_ROUTING,
> -                                      priority, ds_cstr(&match),
> -                                      ds_cstr(&actions), stage_hint,
> -                                      lflow_ref);
> +    ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING,
> +                            priority, ds_cstr(&match),
> +                            ds_cstr(&actions), stage_hint,
> +                            lflow_ref);
>      if (op && op->has_bfd) {
>          ds_put_format(&match, " && udp.dst == 3784");
> -        ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
> -                                          S_ROUTER_IN_IP_ROUTING,
> -                                          priority + 1, ds_cstr(&match),
> -                                          ds_cstr(&common_actions),\
> -                                          stage_hint, lflow_ref);
> +        ovn_lflow_add_with_hint(lflows, op->od,
> +                                S_ROUTER_IN_IP_ROUTING,
> +                                priority + 1, ds_cstr(&match),
> +                                ds_cstr(&common_actions),\
> +                                stage_hint, lflow_ref);
>      }
>      ds_destroy(&match);
>      ds_destroy(&common_actions);
> @@ -10856,7 +11007,8 @@ add_route(struct lflow_table *lflows, struct
ovn_datapath *od,
>  static void
>  build_static_route_flow(struct lflow_table *lflows, struct ovn_datapath
*od,
>                          const struct hmap *lr_ports,
> -                        const struct parsed_route *route_)
> +                        const struct parsed_route *route_,
> +                        struct lflow_ref *lflow_ref)
>  {
>      const char *lrp_addr_s = NULL;
>      struct ovn_port *out_port = NULL;
> @@ -10880,7 +11032,7 @@ build_static_route_flow(struct lflow_table
*lflows, struct ovn_datapath *od,
>      add_route(lflows, route_->is_discard_route ? od : out_port->od,
out_port,
>                lrp_addr_s, prefix_s, route_->plen, route->nexthop,
>                route_->is_src_route, route_->route_table_id,
&route->header_,
> -              route_->is_discard_route, ofs, NULL);
> +              route_->is_discard_route, ofs, lflow_ref);
>
>      free(prefix_s);
>  }
> @@ -10956,7 +11108,8 @@ lrouter_use_common_zone(const struct ovn_datapath
*od)
>  static void
>  build_distr_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx
*ctx,
>                                       enum lrouter_nat_lb_flow_type type,
> -                                     struct ovn_datapath *od)
> +                                     struct ovn_datapath *od,
> +                                     struct lflow_ref *lflow_ref)
>  {
>      struct ovn_port *dgp = od->l3dgw_ports[0];
>
> @@ -10995,7 +11148,8 @@ build_distr_lrouter_nat_flows_for_lb(struct
lrouter_nat_lb_flows_ctx *ctx,
>
>      ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT,
ctx->prio,
>                                ds_cstr(ctx->new_match),
ctx->new_action[type],
> -                              NULL, meter, &ctx->lb->nlb->header_);
> +                              NULL, meter, &ctx->lb->nlb->header_,
> +                              lflow_ref);
>
>      ds_truncate(ctx->new_match, new_match_len);
>
> @@ -11014,7 +11168,8 @@ build_distr_lrouter_nat_flows_for_lb(struct
lrouter_nat_lb_flows_ctx *ctx,
>      ovn_lflow_add_with_hint(ctx->lflows, od, S_ROUTER_IN_GW_REDIRECT,
>                              200, ds_cstr(ctx->undnat_match),
>                              ds_cstr(ctx->gw_redir_action),
> -                            &ctx->lb->nlb->header_);
> +                            &ctx->lb->nlb->header_,
> +                            lflow_ref);
>      ds_truncate(ctx->undnat_match, undnat_match_len);
>
>      ds_put_format(ctx->undnat_match, ") && (inport == %s || outport ==
%s)"
> @@ -11022,7 +11177,8 @@ build_distr_lrouter_nat_flows_for_lb(struct
lrouter_nat_lb_flows_ctx *ctx,
>                    dgp->cr_port->json_key);
>      ovn_lflow_add_with_hint(ctx->lflows, od, S_ROUTER_OUT_UNDNAT, 120,
>                              ds_cstr(ctx->undnat_match), undnat_action,
> -                            &ctx->lb->nlb->header_);
> +                            &ctx->lb->nlb->header_,
> +                            lflow_ref);
>      ds_truncate(ctx->undnat_match, undnat_match_len);
>  }
>
> @@ -11030,7 +11186,8 @@ static void
>  build_gw_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx,
>                                    enum lrouter_nat_lb_flow_type type,
>                                    const struct ovn_datapaths
*lr_datapaths,
> -                                  const unsigned long *dp_bitmap)
> +                                  const unsigned long *dp_bitmap,
> +                                  struct lflow_ref *lflow_ref)
>  {
>      unsigned long *dp_non_meter = NULL;
>      bool build_non_meter = false;
> @@ -11056,14 +11213,14 @@ build_gw_lrouter_nat_flows_for_lb(struct
lrouter_nat_lb_flows_ctx *ctx,
>              bitmap_set0(dp_non_meter, index);
>              ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT,
>                      ctx->prio, ds_cstr(ctx->new_match),
ctx->new_action[type],
> -                    NULL, meter, &ctx->lb->nlb->header_);
> +                    NULL, meter, &ctx->lb->nlb->header_, lflow_ref);
>          }
>      }
>      if (!ctx->reject || build_non_meter) {
>          ovn_lflow_add_with_dp_group(ctx->lflows,
>              dp_non_meter ? dp_non_meter : dp_bitmap,
ods_size(lr_datapaths),
>              S_ROUTER_IN_DNAT, ctx->prio, ds_cstr(ctx->new_match),
> -            ctx->new_action[type], &ctx->lb->nlb->header_);
> +            ctx->new_action[type], &ctx->lb->nlb->header_, lflow_ref);
>      }
>      bitmap_free(dp_non_meter);
>  }
> @@ -11078,7 +11235,8 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip
*lb_vip,
>                                 struct ds *match, struct ds *action,
>                                 const struct shash *meter_groups,
>                                 const struct chassis_features *features,
> -                               const struct hmap *svc_monitor_map)
> +                               const struct hmap *svc_monitor_map,
> +                               struct lflow_ref *lflow_ref)
>  {
>      const struct ovn_northd_lb *lb = lb_dps->lb;
>      bool ipv4 = lb_vip->address_family == AF_INET;
> @@ -11196,7 +11354,7 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip
*lb_vip,
>          if (!od->n_l3dgw_ports) {
>              bitmap_set1(gw_dp_bitmap[type], index);
>          } else {
> -            build_distr_lrouter_nat_flows_for_lb(&ctx, type, od);
> +            build_distr_lrouter_nat_flows_for_lb(&ctx, type, od,
lflow_ref);
>          }
>
>          if (lb->affinity_timeout) {
> @@ -11217,16 +11375,17 @@ build_lrouter_nat_flows_for_lb(struct
ovn_lb_vip *lb_vip,
>               * S_ROUTER_IN_DNAT stage. */
>              ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, 120,
>                                      ds_cstr(&unsnat_match), "next;",
> -                                    &lb->nlb->header_);
> +                                    &lb->nlb->header_, lflow_ref);
>          }
>      }
>
>      for (size_t type = 0; type < LROUTER_NAT_LB_FLOW_MAX; type++) {
>          build_gw_lrouter_nat_flows_for_lb(&ctx, type, lr_datapaths,
> -                                          gw_dp_bitmap[type]);
> +                                          gw_dp_bitmap[type],
> +                                          lflow_ref);
>          build_lb_affinity_lr_flows(lflows, lb, lb_vip, ds_cstr(match),
>                                     aff_action[type], aff_dp_bitmap[type],
> -                                   lr_datapaths);
> +                                   lr_datapaths, lflow_ref);
>      }
>
>      ds_destroy(&unsnat_match);
> @@ -11248,7 +11407,8 @@ build_lswitch_flows_for_lb(struct
ovn_lb_datapaths *lb_dps,
>                             const struct ovn_datapaths *ls_datapaths,
>                             const struct chassis_features *features,
>                             const struct hmap *svc_monitor_map,
> -                           struct ds *match, struct ds *action)
> +                           struct ds *match, struct ds *action,
> +                           struct lflow_ref *lflow_ref)
>  {
>      if (!lb_dps->n_nb_ls) {
>          return;
> @@ -11274,7 +11434,8 @@ build_lswitch_flows_for_lb(struct
ovn_lb_datapaths *lb_dps,
>                                        copp_meter_get(COPP_EVENT_ELB,
>                                                       od->nbs->copp,
>                                                       meter_groups),
> -                                      &lb->nlb->header_);
> +                                      &lb->nlb->header_,
> +                                      lflow_ref);
>          }
>          /* Ignore L4 port information in the key because fragmented
packets
>           * may not have L4 information.  The pre-stateful table will send
> @@ -11289,9 +11450,9 @@ build_lswitch_flows_for_lb(struct
ovn_lb_datapaths *lb_dps,
>       * connection, so it is okay if we do not hit the above match on
>       * REGBIT_CONNTRACK_COMMIT. */
>      build_lb_rules_pre_stateful(lflows, lb_dps,
features->ct_no_masked_label,
> -                                ls_datapaths, match, action);
> +                                ls_datapaths, match, action, lflow_ref);
>      build_lb_rules(lflows, lb_dps, ls_datapaths, features, match, action,
> -                   meter_groups, svc_monitor_map);
> +                   meter_groups, svc_monitor_map, lflow_ref);
>  }
>
>  /* If there are any load balancing rules, we should send the packet to
> @@ -11306,7 +11467,8 @@ static void
>  build_lrouter_defrag_flows_for_lb(struct ovn_lb_datapaths *lb_dps,
>                                    struct lflow_table *lflows,
>                                    const struct ovn_datapaths
*lr_datapaths,
> -                                  struct ds *match)
> +                                  struct ds *match,
> +                                  struct lflow_ref *lflow_ref)
>  {
>      if (!lb_dps->n_nb_lr) {
>          return;
> @@ -11324,7 +11486,7 @@ build_lrouter_defrag_flows_for_lb(struct
ovn_lb_datapaths *lb_dps,
>          ovn_lflow_add_with_dp_group(
>              lflows, lb_dps->nb_lr_map, ods_size(lr_datapaths),
>              S_ROUTER_IN_DEFRAG, prio, ds_cstr(match), "ct_dnat;",
> -            &lb_dps->lb->nlb->header_);
> +            &lb_dps->lb->nlb->header_, lflow_ref);
>      }
>  }
>
> @@ -11336,7 +11498,8 @@ build_lrouter_flows_for_lb(struct
ovn_lb_datapaths *lb_dps,
>                             const struct lr_stateful_table *lr_sful_table,
>                             const struct chassis_features *features,
>                             const struct hmap *svc_monitor_map,
> -                           struct ds *match, struct ds *action)
> +                           struct ds *match, struct ds *action,
> +                           struct lflow_ref *lflow_ref)
>  {
>      size_t index;
>
> @@ -11351,7 +11514,7 @@ build_lrouter_flows_for_lb(struct
ovn_lb_datapaths *lb_dps,
>          build_lrouter_nat_flows_for_lb(lb_vip, lb_dps, &lb->vips_nb[i],
>                                         lr_datapaths, lr_sful_table,
lflows, match,
>                                         action, meter_groups, features,
> -                                       svc_monitor_map);
> +                                       svc_monitor_map, lflow_ref);
>
>          if (!build_empty_lb_event_flow(lb_vip, lb, match, action)) {
>              continue;
> @@ -11366,7 +11529,7 @@ build_lrouter_flows_for_lb(struct
ovn_lb_datapaths *lb_dps,
>                                        copp_meter_get(COPP_EVENT_ELB,
>                                                       od->nbr->copp,
>                                                       meter_groups),
> -                                      &lb->nlb->header_);
> +                                      &lb->nlb->header_, lflow_ref);
>          }
>      }
>
> @@ -11375,7 +11538,8 @@ build_lrouter_flows_for_lb(struct
ovn_lb_datapaths *lb_dps,
>              struct ovn_datapath *od = lr_datapaths->array[index];
>
>              ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 120,
> -                          "flags.skip_snat_for_lb == 1 && ip", "next;");
> +                          "flags.skip_snat_for_lb == 1 && ip", "next;",
> +                          lflow_ref);
>          }
>      }
>  }
> @@ -11490,7 +11654,8 @@ static inline void
>  lrouter_nat_add_ext_ip_match(const struct ovn_datapath *od,
>                               struct lflow_table *lflows, struct ds
*match,
>                               const struct nbrec_nat *nat,
> -                             bool is_v6, bool is_src, int cidr_bits)
> +                             bool is_v6, bool is_src, int cidr_bits,
> +                             struct lflow_ref *lflow_ref)
>  {
>      struct nbrec_address_set *allowed_ext_ips = nat->allowed_ext_ips;
>      struct nbrec_address_set *exempted_ext_ips = nat->exempted_ext_ips;
> @@ -11541,7 +11706,7 @@ lrouter_nat_add_ext_ip_match(const struct
ovn_datapath *od,
>
>          ovn_lflow_add_with_hint(lflows, od, stage, priority,
>                                  ds_cstr(&match_exempt), "next;",
> -                                &nat->header_);
> +                                &nat->header_, lflow_ref);
>          ds_destroy(&match_exempt);
>      }
>  }
> @@ -11555,7 +11720,8 @@ build_lrouter_arp_flow(const struct ovn_datapath
*od, struct ovn_port *op,
>                         const char *ip_address, const char *eth_addr,
>                         struct ds *extra_match, bool drop, uint16_t
priority,
>                         const struct ovsdb_idl_row *hint,
> -                       struct lflow_table *lflows)
> +                       struct lflow_table *lflows,
> +                       struct lflow_ref *lflow_ref)
>  {
>      struct ds match = DS_EMPTY_INITIALIZER;
>      struct ds actions = DS_EMPTY_INITIALIZER;
> @@ -11587,7 +11753,8 @@ build_lrouter_arp_flow(const struct ovn_datapath
*od, struct ovn_port *op,
>      }
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority,
> -                            ds_cstr(&match), ds_cstr(&actions), hint);
> +                            ds_cstr(&match), ds_cstr(&actions), hint,
> +                            lflow_ref);
>
>      ds_destroy(&match);
>      ds_destroy(&actions);
> @@ -11606,7 +11773,8 @@ build_lrouter_nd_flow(const struct ovn_datapath
*od, struct ovn_port *op,
>                        struct ds *extra_match, bool drop, uint16_t
priority,
>                        const struct ovsdb_idl_row *hint,
>                        struct lflow_table *lflows,
> -                      const struct shash *meter_groups)
> +                      const struct shash *meter_groups,
> +                      struct lflow_ref *lflow_ref)
>  {
>      struct ds match = DS_EMPTY_INITIALIZER;
>      struct ds actions = DS_EMPTY_INITIALIZER;
> @@ -11629,7 +11797,8 @@ build_lrouter_nd_flow(const struct ovn_datapath
*od, struct ovn_port *op,
>      if (drop) {
>          ds_put_cstr(&actions, debug_drop_action());
>          ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT,
priority,
> -                                ds_cstr(&match), ds_cstr(&actions),
hint);
> +                                ds_cstr(&match), ds_cstr(&actions), hint,
> +                                lflow_ref);
>      } else {
>          ds_put_format(&actions,
>                        "%s { "
> @@ -11647,7 +11816,7 @@ build_lrouter_nd_flow(const struct ovn_datapath
*od, struct ovn_port *op,
>                                    ds_cstr(&match), ds_cstr(&actions),
NULL,
>                                    copp_meter_get(COPP_ND_NA,
od->nbr->copp,
>                                                   meter_groups),
> -                                  hint);
> +                                  hint, lflow_ref);
>      }
>
>      ds_destroy(&match);
> @@ -11658,7 +11827,8 @@ static void
>  build_lrouter_nat_arp_nd_flow(const struct ovn_datapath *od,
>                                struct ovn_nat *nat_entry,
>                                struct lflow_table *lflows,
> -                              const struct shash *meter_groups)
> +                              const struct shash *meter_groups,
> +                              struct lflow_ref *lflow_ref)
>  {
>      struct lport_addresses *ext_addrs = &nat_entry->ext_addrs;
>      const struct nbrec_nat *nat = nat_entry->nb;
> @@ -11668,12 +11838,14 @@ build_lrouter_nat_arp_nd_flow(const struct
ovn_datapath *od,
>                                ext_addrs->ipv6_addrs[0].addr_s,
>                                ext_addrs->ipv6_addrs[0].sn_addr_s,
>                                REG_INPORT_ETH_ADDR, NULL, false, 90,
> -                              &nat->header_, lflows, meter_groups);
> +                              &nat->header_, lflows, meter_groups,
> +                              lflow_ref);
>      } else {
>          build_lrouter_arp_flow(od, NULL,
>                                 ext_addrs->ipv4_addrs[0].addr_s,
>                                 REG_INPORT_ETH_ADDR, NULL, false, 90,
> -                               &nat->header_, lflows);
> +                               &nat->header_, lflows,
> +                               lflow_ref);
>      }
>  }
>
> @@ -11681,7 +11853,8 @@ static void
>  build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op,
>                                     struct ovn_nat *nat_entry,
>                                     struct lflow_table *lflows,
> -                                   const struct shash *meter_groups)
> +                                   const struct shash *meter_groups,
> +                                   struct lflow_ref *lflow_ref)
>  {
>      struct lport_addresses *ext_addrs = &nat_entry->ext_addrs;
>      const struct nbrec_nat *nat = nat_entry->nb;
> @@ -11729,21 +11902,25 @@ build_lrouter_port_nat_arp_nd_flow(struct
ovn_port *op,
>                                ext_addrs->ipv6_addrs[0].addr_s,
>                                ext_addrs->ipv6_addrs[0].sn_addr_s,
>                                mac_s, &match, false, 92,
> -                              &nat->header_, lflows, meter_groups);
> +                              &nat->header_, lflows, meter_groups,
> +                              lflow_ref);
>          build_lrouter_nd_flow(op->od, op, "nd_na",
>                                ext_addrs->ipv6_addrs[0].addr_s,
>                                ext_addrs->ipv6_addrs[0].sn_addr_s,
>                                mac_s, NULL, true, 91,
> -                              &nat->header_, lflows, meter_groups);
> +                              &nat->header_, lflows, meter_groups,
> +                              lflow_ref);
>      } else {
>          build_lrouter_arp_flow(op->od, op,
>                                 ext_addrs->ipv4_addrs[0].addr_s,
>                                 mac_s, &match, false, 92,
> -                               &nat->header_, lflows);
> +                               &nat->header_, lflows,
> +                               lflow_ref);
>          build_lrouter_arp_flow(op->od, op,
>                                 ext_addrs->ipv4_addrs[0].addr_s,
>                                 mac_s, NULL, true, 91,
> -                               &nat->header_, lflows);
> +                               &nat->header_, lflows,
> +                               lflow_ref);
>      }
>
>      ds_destroy(&match);
> @@ -11754,7 +11931,8 @@ build_lrouter_drop_own_dest(struct ovn_port *op,
>                              const struct lr_stateful_record *lr_sful_rec,
>                              enum ovn_stage stage,
>                              uint16_t priority, bool drop_snat_ip,
> -                            struct lflow_table *lflows)
> +                            struct lflow_table *lflows,
> +                            struct lflow_ref *lflow_ref)
>  {
>      struct ds match_ips = DS_EMPTY_INITIALIZER;
>
> @@ -11781,7 +11959,8 @@ build_lrouter_drop_own_dest(struct ovn_port *op,
>              char *match = xasprintf("ip4.dst == {%s}",
ds_cstr(&match_ips));
>              ovn_lflow_add_with_hint(lflows, op->od, stage, priority,
>                                      match, debug_drop_action(),
> -                                    &op->nbrp->header_);
> +                                    &op->nbrp->header_,
> +                                    lflow_ref);
>              free(match);
>          }
>      }
> @@ -11811,7 +11990,8 @@ build_lrouter_drop_own_dest(struct ovn_port *op,
>              char *match = xasprintf("ip6.dst == {%s}",
ds_cstr(&match_ips));
>              ovn_lflow_add_with_hint(lflows, op->od, stage, priority,
>                                      match, debug_drop_action(),
> -                                    &op->nbrp->header_);
> +                                    &op->nbrp->header_,
> +                                    lflow_ref);
>              free(match);
>          }
>      }
> @@ -11822,14 +12002,15 @@ static void
>  build_lrouter_force_snat_flows(struct lflow_table *lflows,
>                                 const struct ovn_datapath *od,
>                                 const char *ip_version, const char
*ip_addr,
> -                               const char *context)
> +                               const char *context,
> +                               struct lflow_ref *lflow_ref)
>  {
>      struct ds match = DS_EMPTY_INITIALIZER;
>      struct ds actions = DS_EMPTY_INITIALIZER;
>      ds_put_format(&match, "ip%s && ip%s.dst == %s",
>                    ip_version, ip_version, ip_addr);
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 110,
> -                  ds_cstr(&match), "ct_snat;");
> +                  ds_cstr(&match), "ct_snat;", lflow_ref);
>
>      /* Higher priority rules to force SNAT with the IP addresses
>       * configured in the Gateway router.  This only takes effect
> @@ -11839,7 +12020,8 @@ build_lrouter_force_snat_flows(struct lflow_table
*lflows,
>                    context, ip_version);
>      ds_put_format(&actions, "ct_snat(%s);", ip_addr);
>      ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 100,
> -                  ds_cstr(&match), ds_cstr(&actions));
> +                  ds_cstr(&match), ds_cstr(&actions),
> +                  lflow_ref);
>
>      ds_destroy(&match);
>      ds_destroy(&actions);
> @@ -11849,7 +12031,8 @@ static void
>  build_lrouter_force_snat_flows_op(struct ovn_port *op,
>                                    const struct lr_nat_record *lrnat_rec,
>                                    struct lflow_table *lflows,
> -                                  struct ds *match, struct ds *actions)
> +                                  struct ds *match, struct ds *actions,
> +                                  struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbrp);
>      if (!op->peer || !lrnat_rec->lb_force_snat_router_ip) {
> @@ -11863,7 +12046,7 @@ build_lrouter_force_snat_flows_op(struct ovn_port
*op,
>          ds_put_format(match, "inport == %s && ip4.dst == %s",
>                        op->json_key,
op->lrp_networks.ipv4_addrs[0].addr_s);
>          ovn_lflow_add(lflows, op->od, S_ROUTER_IN_UNSNAT, 110,
> -                      ds_cstr(match), "ct_snat;");
> +                      ds_cstr(match), "ct_snat;", lflow_ref);
>
>          ds_clear(match);
>
> @@ -11875,7 +12058,8 @@ build_lrouter_force_snat_flows_op(struct ovn_port
*op,
>          ds_put_format(actions, "ct_snat(%s);",
>                        op->lrp_networks.ipv4_addrs[0].addr_s);
>          ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_SNAT, 110,
> -                      ds_cstr(match), ds_cstr(actions));
> +                      ds_cstr(match), ds_cstr(actions),
> +                      lflow_ref);
>          if (op->lrp_networks.n_ipv4_addrs > 1) {
>              static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1,
5);
>              VLOG_WARN_RL(&rl, "Logical router port %s is configured with
"
> @@ -11895,7 +12079,7 @@ build_lrouter_force_snat_flows_op(struct ovn_port
*op,
>          ds_put_format(match, "inport == %s && ip6.dst == %s",
>                        op->json_key,
op->lrp_networks.ipv6_addrs[0].addr_s);
>          ovn_lflow_add(lflows, op->od, S_ROUTER_IN_UNSNAT, 110,
> -                      ds_cstr(match), "ct_snat;");
> +                      ds_cstr(match), "ct_snat;", lflow_ref);
>
>          ds_clear(match);
>
> @@ -11907,7 +12091,8 @@ build_lrouter_force_snat_flows_op(struct ovn_port
*op,
>          ds_put_format(actions, "ct_snat(%s);",
>                        op->lrp_networks.ipv6_addrs[0].addr_s);
>          ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_SNAT, 110,
> -                      ds_cstr(match), ds_cstr(actions));
> +                      ds_cstr(match), ds_cstr(actions),
> +                      lflow_ref);
>          if (op->lrp_networks.n_ipv6_addrs > 2) {
>              static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1,
5);
>              VLOG_WARN_RL(&rl, "Logical router port %s is configured with
"
> @@ -11921,7 +12106,8 @@ build_lrouter_force_snat_flows_op(struct ovn_port
*op,
>
>  static void
>  build_lrouter_bfd_flows(struct lflow_table *lflows, struct ovn_port *op,
> -                        const struct shash *meter_groups)
> +                        const struct shash *meter_groups,
> +                        struct lflow_ref *lflow_ref)
>  {
>      if (!op->has_bfd) {
>          return;
> @@ -11936,7 +12122,8 @@ build_lrouter_bfd_flows(struct lflow_table
*lflows, struct ovn_port *op,
>                        ds_cstr(&ip_list));
>          ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
110,
>                                  ds_cstr(&match), "next; ",
> -                                &op->nbrp->header_);
> +                                &op->nbrp->header_,
> +                                lflow_ref);
>          ds_clear(&match);
>          ds_put_format(&match, "ip4.dst == %s && udp.dst == 3784",
>                        ds_cstr(&ip_list));
> @@ -11944,7 +12131,8 @@ build_lrouter_bfd_flows(struct lflow_table
*lflows, struct ovn_port *op,
>                                    ds_cstr(&match), "handle_bfd_msg(); ",
NULL,
>                                    copp_meter_get(COPP_BFD,
op->od->nbr->copp,
>                                                   meter_groups),
> -                                  &op->nbrp->header_);
> +                                  &op->nbrp->header_,
> +                                  lflow_ref);
>      }
>      if (op->lrp_networks.n_ipv6_addrs) {
>          ds_clear(&ip_list);
> @@ -11955,7 +12143,8 @@ build_lrouter_bfd_flows(struct lflow_table
*lflows, struct ovn_port *op,
>                        ds_cstr(&ip_list));
>          ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
110,
>                                  ds_cstr(&match), "next; ",
> -                                &op->nbrp->header_);
> +                                &op->nbrp->header_,
> +                                lflow_ref);
>          ds_clear(&match);
>          ds_put_format(&match, "ip6.dst == %s && udp.dst == 3784",
>                        ds_cstr(&ip_list));
> @@ -11963,7 +12152,8 @@ build_lrouter_bfd_flows(struct lflow_table
*lflows, struct ovn_port *op,
>                                    ds_cstr(&match), "handle_bfd_msg(); ",
NULL,
>                                    copp_meter_get(COPP_BFD,
op->od->nbr->copp,
>                                                   meter_groups),
> -                                  &op->nbrp->header_);
> +                                  &op->nbrp->header_,
> +                                  lflow_ref);
>      }
>
>      ds_destroy(&ip_list);
> @@ -11975,16 +12165,19 @@ build_lrouter_bfd_flows(struct lflow_table
*lflows, struct ovn_port *op,
>   */
>  static void
>  build_adm_ctrl_flows_for_lrouter(
> -        struct ovn_datapath *od, struct lflow_table *lflows)
> +        struct ovn_datapath *od, struct lflow_table *lflows,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
>      /* Logical VLANs not supported.
>       * Broadcast/multicast source address is invalid. */
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 100,
> -                  "vlan.present || eth.src[40]", debug_drop_action());
> +                  "vlan.present || eth.src[40]", debug_drop_action(),
> +                  lflow_ref);
>
>      /* Default action for L2 security is to drop. */
> -    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ADMISSION);
> +    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ADMISSION,
> +                               lflow_ref);
>  }
>
>  static int
> @@ -12018,11 +12211,12 @@ build_gateway_get_l2_hdr_size(struct ovn_port
*op)
>  /* All 'gateway_mtu' and 'gateway_mtu_bypass' flows should be built with
this
>   * function.
>   */
> -static void OVS_PRINTF_FORMAT(9, 10)
> +static void OVS_PRINTF_FORMAT(10, 11)
>  build_gateway_mtu_flow(struct lflow_table *lflows, struct ovn_port *op,
>                         enum ovn_stage stage, uint16_t prio_low,
>                         uint16_t prio_high, struct ds *match,
>                         struct ds *actions, const struct ovsdb_idl_row
*hint,
> +                       struct lflow_ref *lflow_ref,
>                         const char *extra_actions_fmt, ...)
>  {
>      int gw_mtu = smap_get_int(&op->nbrp->options, "gateway_mtu", 0);
> @@ -12040,7 +12234,7 @@ build_gateway_mtu_flow(struct lflow_table
*lflows, struct ovn_port *op,
>      ds_put_format_valist(actions, extra_actions_fmt, extra_actions_args);
>      ovn_lflow_add_with_hint(lflows, op->od, stage, prio_low,
>                              ds_cstr(match), ds_cstr(actions),
> -                            hint);
> +                            hint, lflow_ref);
>
>      if (gw_mtu > 0) {
>          const char *gw_mtu_bypass = smap_get(&op->nbrp->options,
> @@ -12052,7 +12246,7 @@ build_gateway_mtu_flow(struct lflow_table
*lflows, struct ovn_port *op,
>              ds_put_format(match, " && (%s)", gw_mtu_bypass);
>              ovn_lflow_add_with_hint(lflows, op->od, stage, prio_high,
>                                      ds_cstr(match), ds_cstr(actions),
> -                                    hint);
> +                                    hint, lflow_ref);
>          }
>      }
>      va_end(extra_actions_args);
> @@ -12081,7 +12275,8 @@ consider_l3dgw_port_is_centralized(struct
ovn_port *op)
>  static void
>  build_adm_ctrl_flows_for_lrouter_port(
>          struct ovn_port *op, struct lflow_table *lflows,
> -        struct ds *match, struct ds *actions)
> +        struct ds *match, struct ds *actions,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbrp);
>
> @@ -12105,6 +12300,7 @@ build_adm_ctrl_flows_for_lrouter_port(
>      ds_put_format(match, "eth.mcast && inport == %s", op->json_key);
>      build_gateway_mtu_flow(lflows, op, S_ROUTER_IN_ADMISSION, 50, 55,
>                             match, actions, &op->nbrp->header_,
> +                           lflow_ref,
>                             REG_INPORT_ETH_ADDR " = %s; next;",
>                             op->lrp_networks.ea_s);
>
> @@ -12125,6 +12321,7 @@ build_adm_ctrl_flows_for_lrouter_port(
>      }
>      build_gateway_mtu_flow(lflows, op, S_ROUTER_IN_ADMISSION, 50, 55,
>                             match, actions, &op->nbrp->header_,
> +                           lflow_ref,
>                             REG_INPORT_ETH_ADDR " = %s; next;",
>                             op->lrp_networks.ea_s);
>  }
> @@ -12136,7 +12333,8 @@ static void
>  build_neigh_learning_flows_for_lrouter(
>          struct ovn_datapath *od, struct lflow_table *lflows,
>          struct ds *match, struct ds *actions,
> -        const struct shash *meter_groups)
> +        const struct shash *meter_groups,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
>
> @@ -12183,7 +12381,7 @@ build_neigh_learning_flows_for_lrouter(
>                    learn_from_arp_request ? "" :
>                    REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; ");
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100,
> -                  "arp.op == 2", ds_cstr(actions));
> +                  "arp.op == 2", ds_cstr(actions), lflow_ref);
>
>      ds_clear(actions);
>      ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT
> @@ -12191,7 +12389,7 @@ build_neigh_learning_flows_for_lrouter(
>                    learn_from_arp_request ? "" :
>                    REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; ");
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_na",
> -                  ds_cstr(actions));
> +                  ds_cstr(actions), lflow_ref);
>
>      if (!learn_from_arp_request) {
>          /* Add flow to skip GARP LLA if we don't know it already.
> @@ -12208,7 +12406,7 @@ build_neigh_learning_flows_for_lrouter(
>                                 " = lookup_nd_ip(inport, ip6.src);
next;");
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 110,
>                        "nd_na && ip6.src == fe80::/10 && ip6.dst ==
ff00::/8",
> -                      ds_cstr(actions));
> +                      ds_cstr(actions), lflow_ref);
>      }
>
>      ds_clear(actions);
> @@ -12218,12 +12416,13 @@ build_neigh_learning_flows_for_lrouter(
>                    REGBIT_LOOKUP_NEIGHBOR_IP_RESULT
>                    " = lookup_nd_ip(inport, ip6.src); ");
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_ns",
> -                  ds_cstr(actions));
> +                  ds_cstr(actions), lflow_ref);
>
>      /* For other packet types, we can skip neighbor learning.
>       * So set REGBIT_LOOKUP_NEIGHBOR_RESULT to 1. */
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 0, "1",
> -                  REGBIT_LOOKUP_NEIGHBOR_RESULT" = 1; next;");
> +                  REGBIT_LOOKUP_NEIGHBOR_RESULT" = 1; next;",
> +                  lflow_ref);
>
>      /* Flows for LEARN_NEIGHBOR. */
>      /* Skip Neighbor learning if not required. */
> @@ -12232,33 +12431,40 @@ build_neigh_learning_flows_for_lrouter(
>                    learn_from_arp_request ? "" :
>                    " || "REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" == 0");
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 100,
> -                  ds_cstr(match), "mac_cache_use; next;");
> +                  ds_cstr(match), "mac_cache_use; next;",
> +                  lflow_ref);
>
>      ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
>                        "arp", "put_arp(inport, arp.spa, arp.sha); next;",
>                        copp_meter_get(COPP_ARP, od->nbr->copp,
> -                                     meter_groups));
> +                                     meter_groups),
> +                      lflow_ref);
>
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 95,
> -                  "nd_ns && (ip6.src == 0 || nd.sll == 0)", "next;");
> +                  "nd_ns && (ip6.src == 0 || nd.sll == 0)", "next;",
> +                  lflow_ref);
>
>      ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 95,
>                        "nd_na && nd.tll == 0",
>                        "put_nd(inport, nd.target, eth.src); next;",
>                        copp_meter_get(COPP_ND_NA, od->nbr->copp,
> -                                     meter_groups));
> +                                     meter_groups),
> +                      lflow_ref);
>
>      ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
>                        "nd_na", "put_nd(inport, nd.target, nd.tll);
next;",
>                        copp_meter_get(COPP_ND_NA, od->nbr->copp,
> -                                     meter_groups));
> +                                     meter_groups),
> +                      lflow_ref);
>
>      ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
>                        "nd_ns", "put_nd(inport, ip6.src, nd.sll); next;",
>                        copp_meter_get(COPP_ND_NS, od->nbr->copp,
> -                                     meter_groups));
> +                                     meter_groups),
> +                      lflow_ref);
>
> -    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR);
> +    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR,
> +                               lflow_ref);
>  }
>
>  /* Logical router ingress Table 1: Neighbor lookup lflows
> @@ -12266,7 +12472,8 @@ build_neigh_learning_flows_for_lrouter(
>  static void
>  build_neigh_learning_flows_for_lrouter_port(
>          struct ovn_port *op, struct lflow_table *lflows,
> -        struct ds *match, struct ds *actions)
> +        struct ds *match, struct ds *actions,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbrp);
>
> @@ -12298,7 +12505,8 @@ build_neigh_learning_flows_for_lrouter_port(
>              ovn_lflow_add_with_hint(lflows, op->od,
>                                      S_ROUTER_IN_LOOKUP_NEIGHBOR, 110,
>                                      ds_cstr(match), actions_s,
> -                                    &op->nbrp->header_);
> +                                    &op->nbrp->header_,
> +                                    lflow_ref);
>          }
>          ds_clear(match);
>          ds_put_format(match,
> @@ -12319,7 +12527,8 @@ build_neigh_learning_flows_for_lrouter_port(
>          ovn_lflow_add_with_hint(lflows, op->od,
>                                  S_ROUTER_IN_LOOKUP_NEIGHBOR, 100,
>                                  ds_cstr(match), ds_cstr(actions),
> -                                &op->nbrp->header_);
> +                                &op->nbrp->header_,
> +                                lflow_ref);
>      }
>  }
>
> @@ -12329,7 +12538,8 @@ static void
>  build_ND_RA_flows_for_lrouter_port(
>          struct ovn_port *op, struct lflow_table *lflows,
>          struct ds *match, struct ds *actions,
> -        const struct shash *meter_groups)
> +        const struct shash *meter_groups,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbrp);
>      if (op->nbrp->peer || !op->peer) {
> @@ -12416,7 +12626,8 @@ build_ND_RA_flows_for_lrouter_port(
>                                    copp_meter_get(COPP_ND_RA_OPTS,
>                                                   op->od->nbr->copp,
>                                                   meter_groups),
> -                                  &op->nbrp->header_);
> +                                  &op->nbrp->header_,
> +                                  lflow_ref);
>          ds_clear(actions);
>          ds_clear(match);
>          ds_put_format(match, "inport == %s && ip6.dst == ff02::2 && "
> @@ -12435,7 +12646,8 @@ build_ND_RA_flows_for_lrouter_port(
>          ovn_lflow_add_with_hint(lflows, op->od,
>                                  S_ROUTER_IN_ND_RA_RESPONSE, 50,
>                                  ds_cstr(match), ds_cstr(actions),
> -                                &op->nbrp->header_);
> +                                &op->nbrp->header_,
> +                                lflow_ref);
>      }
>  }
>
> @@ -12443,22 +12655,26 @@ build_ND_RA_flows_for_lrouter_port(
>   * responder, by default goto next. (priority 0). */
>  static void
>  build_ND_RA_flows_for_lrouter(struct ovn_datapath *od,
> -                              struct lflow_table *lflows)
> +                              struct lflow_table *lflows,
> +                              struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
> -    ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_OPTIONS, 0, "1",
"next;");
> -    ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_RESPONSE, 0, "1",
"next;");
> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_OPTIONS, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_RESPONSE, 0, "1",
"next;",
> +                  lflow_ref);
>  }
>
>  /* Logical router ingress table IP_ROUTING_PRE:
>   * by default goto next. (priority 0). */
>  static void
>  build_ip_routing_pre_flows_for_lrouter(struct ovn_datapath *od,
> -                                       struct lflow_table *lflows)
> +                                       struct lflow_table *lflows,
> +                                       struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_PRE, 0, "1",
> -                  REG_ROUTE_TABLE_ID" = 0; next;");
> +                  REG_ROUTE_TABLE_ID" = 0; next;", lflow_ref);
>  }
>
>  /* Logical router ingress table IP_ROUTING : IP Routing.
> @@ -12482,7 +12698,8 @@ build_ip_routing_pre_flows_for_lrouter(struct
ovn_datapath *od,
>   */
>  static void
>  build_ip_routing_flows_for_lrp(
> -        struct ovn_port *op, struct lflow_table *lflows)
> +        struct ovn_port *op, struct lflow_table *lflows,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbrp);
>      for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
> @@ -12490,7 +12707,7 @@ build_ip_routing_flows_for_lrp(
>                    op->lrp_networks.ipv4_addrs[i].network_s,
>                    op->lrp_networks.ipv4_addrs[i].plen, NULL, false, 0,
>                    &op->nbrp->header_, false, ROUTE_PRIO_OFFSET_CONNECTED,
> -                  NULL);
> +                  lflow_ref);
>      }
>
>      for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
> @@ -12498,7 +12715,7 @@ build_ip_routing_flows_for_lrp(
>                    op->lrp_networks.ipv6_addrs[i].network_s,
>                    op->lrp_networks.ipv6_addrs[i].plen, NULL, false, 0,
>                    &op->nbrp->header_, false, ROUTE_PRIO_OFFSET_CONNECTED,
> -                  NULL);
> +                  lflow_ref);
>      }
>  }
>
> @@ -12563,13 +12780,17 @@ static void
>  build_static_route_flows_for_lrouter(
>          struct ovn_datapath *od, const struct chassis_features *features,
>          struct lflow_table *lflows, const struct hmap *lr_ports,
> -        const struct hmap *bfd_connections)
> +        const struct hmap *bfd_connections,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
> -    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP);
> -    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING);
> +    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP,
> +                               lflow_ref);
> +    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING,
> +                               lflow_ref);
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 150,
> -                  REG_ECMP_GROUP_ID" == 0", "next;");
> +                  REG_ECMP_GROUP_ID" == 0", "next;",
> +                  lflow_ref);
>
>      struct hmap ecmp_groups = HMAP_INITIALIZER(&ecmp_groups);
>      struct hmap unique_routes = HMAP_INITIALIZER(&unique_routes);
> @@ -12579,7 +12800,7 @@ build_static_route_flows_for_lrouter(
>
>      for (int i = 0; i < od->nbr->n_ports; i++) {
>          build_route_table_lflow(od, lflows, od->nbr->ports[i],
> -                                &route_tables);
> +                                &route_tables, lflow_ref);
>      }
>
>      for (int i = 0; i < od->nbr->n_static_routes; i++) {
> @@ -12609,11 +12830,11 @@ build_static_route_flows_for_lrouter(
>          /* add a flow in IP_ROUTING, and one flow for each member in
>           * IP_ROUTING_ECMP. */
>          build_ecmp_route_flow(lflows, od, features->ct_no_masked_label,
> -                              lr_ports, group);
> +                              lr_ports, group, lflow_ref);
>      }
>      const struct unique_routes_node *ur;
>      HMAP_FOR_EACH (ur, hmap_node, &unique_routes) {
> -        build_static_route_flow(lflows, od, lr_ports, ur->route);
> +        build_static_route_flow(lflows, od, lr_ports, ur->route,
lflow_ref);
>      }
>      ecmp_groups_destroy(&ecmp_groups);
>      unique_routes_destroy(&unique_routes);
> @@ -12627,7 +12848,8 @@ build_static_route_flows_for_lrouter(
>  static void
>  build_mcast_lookup_flows_for_lrouter(
>          struct ovn_datapath *od, struct lflow_table *lflows,
> -        struct ds *match, struct ds *actions)
> +        struct ds *match, struct ds *actions,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
>
> @@ -12635,7 +12857,8 @@ build_mcast_lookup_flows_for_lrouter(
>       * i.e., router solicitation and router advertisement.
>       */
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550,
> -                  "nd_rs || nd_ra", debug_drop_action());
> +                  "nd_rs || nd_ra", debug_drop_action(),
> +                  lflow_ref);
>      if (!od->mcast_info.rtr.relay) {
>          return;
>      }
> @@ -12663,7 +12886,8 @@ build_mcast_lookup_flows_for_lrouter(
>          ds_put_format(actions, "outport = \"%s\"; ip.ttl--; next;",
>                        igmp_group->mcgroup.name);
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10500,
> -                      ds_cstr(match), ds_cstr(actions));
> +                      ds_cstr(match), ds_cstr(actions),
> +                      lflow_ref);
>      }
>
>      /* If needed, flood unregistered multicast on statically configured
> @@ -12682,13 +12906,15 @@ build_mcast_lookup_flows_for_lrouter(
>              ds_put_format(match, "eth.src == %s && igmp",
>                            op->lrp_networks.ea_s);
>              ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550,
> -                          ds_cstr(match), debug_drop_action());
> +                          ds_cstr(match), debug_drop_action(),
> +                          lflow_ref);
>
>              ds_clear(match);
>              ds_put_format(match, "eth.src == %s && (mldv1 || mldv2)",
>                            op->lrp_networks.ea_s);
>              ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550,
> -                          ds_cstr(match), debug_drop_action());
> +                          ds_cstr(match), debug_drop_action(),
> +                          lflow_ref);
>          }
>
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10460,
> @@ -12696,23 +12922,27 @@ build_mcast_lookup_flows_for_lrouter(
>                        "clone { "
>                              "outport = \""MC_STATIC"\"; "
>                              "next; "
> -                      "};");
> +                      "};",
> +                      lflow_ref);
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10460,
>                        "mldv1 || mldv2",
>                        "clone { "
>                              "outport = \""MC_STATIC"\"; "
>                              "next; "
> -                      "};");
> +                      "};",
> +                      lflow_ref);
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10450,
>                        "ip4.mcast || ip6.mcast",
>                        "clone { "
>                              "outport = \""MC_STATIC"\"; "
>                              "ip.ttl--; "
>                              "next; "
> -                      "};");
> +                      "};",
> +                      lflow_ref);
>      } else {
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10450,
> -                      "ip4.mcast || ip6.mcast", debug_drop_action());
> +                      "ip4.mcast || ip6.mcast", debug_drop_action(),
> +                      lflow_ref);
>      }
>  }
>
> @@ -12728,16 +12958,20 @@ build_mcast_lookup_flows_for_lrouter(
>  static void
>  build_ingress_policy_flows_for_lrouter(
>          struct ovn_datapath *od, struct lflow_table *lflows,
> -        const struct hmap *lr_ports)
> +        const struct hmap *lr_ports,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
>      /* This is a catch-all rule. It has the lowest priority (0)
>       * does a match-all("1") and pass-through (next) */
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY, 0, "1",
> -                  REG_ECMP_GROUP_ID" = 0; next;");
> +                  REG_ECMP_GROUP_ID" = 0; next;",
> +                  lflow_ref);
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY_ECMP, 150,
> -                  REG_ECMP_GROUP_ID" == 0", "next;");
> -    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_POLICY_ECMP);
> +                  REG_ECMP_GROUP_ID" == 0", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_POLICY_ECMP,
> +                               lflow_ref);
>
>      /* Convert routing policies to flows. */
>      uint16_t ecmp_group_id = 1;
> @@ -12749,11 +12983,11 @@ build_ingress_policy_flows_for_lrouter(
>
>          if (is_ecmp_reroute) {
>              build_ecmp_routing_policy_flows(lflows, od, lr_ports, rule,
> -                                            ecmp_group_id);
> +                                            ecmp_group_id, lflow_ref);
>              ecmp_group_id++;
>          } else {
>              build_routing_policy_flow(lflows, od, lr_ports, rule,
> -                                      &rule->header_);
> +                                      &rule->header_, lflow_ref);
>          }
>      }
>  }
> @@ -12761,21 +12995,26 @@ build_ingress_policy_flows_for_lrouter(
>  /* Local router ingress table ARP_RESOLVE: ARP Resolution. */
>  static void
>  build_arp_resolve_flows_for_lrouter(
> -        struct ovn_datapath *od, struct lflow_table *lflows)
> +        struct ovn_datapath *od, struct lflow_table *lflows,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
>      /* Multicast packets already have the outport set so just advance to
>       * next table (priority 500). */
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 500,
> -                  "ip4.mcast || ip6.mcast", "next;");
> +                  "ip4.mcast || ip6.mcast", "next;",
> +                  lflow_ref);
>
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip4",
> -                  "get_arp(outport, " REG_NEXT_HOP_IPV4 "); next;");
> +                  "get_arp(outport, " REG_NEXT_HOP_IPV4 "); next;",
> +                  lflow_ref);
>
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip6",
> -                  "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;");
> +                  "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;",
> +                  lflow_ref);
>
> -    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ARP_RESOLVE);
> +    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ARP_RESOLVE,
> +                               lflow_ref);
>  }
>
>  static void
> @@ -12808,9 +13047,8 @@ routable_addresses_to_lflows(struct lflow_table
*lflows,
>
>          ds_clear(actions);
>          ds_put_format(actions, "eth.dst = %s; next;", ra.laddrs[i].ea_s);
> -        ovn_lflow_add_with_lflow_ref(lflows, peer->od,
S_ROUTER_IN_ARP_RESOLVE,
> -                                     100, ds_cstr(match),
ds_cstr(actions),
> -                                     lflow_ref);
> +        ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, 100,
> +                      ds_cstr(match), ds_cstr(actions), lflow_ref);
>      }
>      destroy_routable_addresses(&ra);
>  }
> @@ -12829,7 +13067,8 @@ routable_addresses_to_lflows(struct lflow_table
*lflows,
>  static void
>  build_arp_resolve_flows_for_lrp(
>          struct ovn_port *op,
> -        struct lflow_table *lflows, struct ds *match, struct ds *actions)
> +        struct lflow_table *lflows, struct ds *match, struct ds *actions,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbrp);
>      /* This is a logical router port. If next-hop IP address in
> @@ -12854,7 +13093,8 @@ build_arp_resolve_flows_for_lrp(
>              ovn_lflow_add_with_hint(lflows, op->peer->od,
>                                      S_ROUTER_IN_ARP_RESOLVE, 100,
>                                      ds_cstr(match), ds_cstr(actions),
> -                                    &op->nbrp->header_);
> +                                    &op->nbrp->header_,
> +                                    lflow_ref);
>          }
>
>          if (op->lrp_networks.n_ipv6_addrs) {
> @@ -12870,7 +13110,8 @@ build_arp_resolve_flows_for_lrp(
>              ovn_lflow_add_with_hint(lflows, op->peer->od,
>                                      S_ROUTER_IN_ARP_RESOLVE, 100,
>                                      ds_cstr(match), ds_cstr(actions),
> -                                    &op->nbrp->header_);
> +                                    &op->nbrp->header_,
> +                                    lflow_ref);
>          }
>      }
>
> @@ -12895,7 +13136,8 @@ build_arp_resolve_flows_for_lrp(
>              ovn_lflow_add_with_hint(lflows, op->od,
>                                      S_ROUTER_IN_ARP_RESOLVE, 50,
>                                      ds_cstr(match), ds_cstr(actions),
> -                                    &op->nbrp->header_);
> +                                    &op->nbrp->header_,
> +                                    lflow_ref);
>          }
>      }
>  }
> @@ -12945,7 +13187,7 @@ build_arp_resolve_flows_for_lsp(
>
>                      ds_clear(actions);
>                      ds_put_format(actions, "eth.dst = %s; next;", ea_s);
> -                    ovn_lflow_add_with_lflow_ref_hint(lflows, peer->od,
> +                    ovn_lflow_add_with_hint(lflows, peer->od,
>                                              S_ROUTER_IN_ARP_RESOLVE, 100,
>                                              ds_cstr(match),
>                                              ds_cstr(actions),
> @@ -12977,7 +13219,7 @@ build_arp_resolve_flows_for_lsp(
>
>                      ds_clear(actions);
>                      ds_put_format(actions, "eth.dst = %s; next;", ea_s);
> -                    ovn_lflow_add_with_lflow_ref_hint(lflows, peer->od,
> +                    ovn_lflow_add_with_hint(lflows, peer->od,
>                                              S_ROUTER_IN_ARP_RESOLVE, 100,
>                                              ds_cstr(match),
>                                              ds_cstr(actions),
> @@ -13026,7 +13268,7 @@ build_arp_resolve_flows_for_lsp(
>                  ds_clear(actions);
>                  ds_put_format(actions, "eth.dst = %s; next;",
>
 router_port->lrp_networks.ea_s);
> -                ovn_lflow_add_with_lflow_ref_hint(lflows, peer->od,
> +                ovn_lflow_add_with_hint(lflows, peer->od,
>                                          S_ROUTER_IN_ARP_RESOLVE, 100,
>                                          ds_cstr(match), ds_cstr(actions),
>                                          &op->nbsp->header_,
> @@ -13043,7 +13285,7 @@ build_arp_resolve_flows_for_lsp(
>                  ds_clear(actions);
>                  ds_put_format(actions, "eth.dst = %s; next;",
>                                router_port->lrp_networks.ea_s);
> -                ovn_lflow_add_with_lflow_ref_hint(lflows, peer->od,
> +                ovn_lflow_add_with_hint(lflows, peer->od,
>                                          S_ROUTER_IN_ARP_RESOLVE, 100,
>                                          ds_cstr(match), ds_cstr(actions),
>                                          &op->nbsp->header_,
> @@ -13104,7 +13346,8 @@ build_icmperr_pkt_big_flows(struct ovn_port *op,
int mtu,
>                              struct lflow_table *lflows,
>                              const struct shash *meter_groups, struct ds
*match,
>                              struct ds *actions, enum ovn_stage stage,
> -                            struct ovn_port *outport)
> +                            struct ovn_port *outport,
> +                            struct lflow_ref *lflow_ref)
>  {
>      char *outport_match = outport ? xasprintf("outport == %s && ",
>                                                outport->json_key)
> @@ -13147,7 +13390,8 @@ build_icmperr_pkt_big_flows(struct ovn_port *op,
int mtu,
>                                          COPP_ICMP4_ERR,
>                                          op->od->nbr->copp,
>                                          meter_groups),
> -                                  &op->nbrp->header_);
> +                                  &op->nbrp->header_,
> +                                  lflow_ref);
>      }
>
>      char *ip6_src = NULL;
> @@ -13187,7 +13431,8 @@ build_icmperr_pkt_big_flows(struct ovn_port *op,
int mtu,
>                                          COPP_ICMP6_ERR,
>                                          op->od->nbr->copp,
>                                          meter_groups),
> -                                  &op->nbrp->header_);
> +                                  &op->nbrp->header_,
> +                                  lflow_ref);
>      }
>      free(outport_match);
>  }
> @@ -13198,7 +13443,8 @@ build_check_pkt_len_flows_for_lrp(struct ovn_port
*op,
>                                    const struct hmap *lr_ports,
>                                    const struct shash *meter_groups,
>                                    struct ds *match,
> -                                  struct ds *actions)
> +                                  struct ds *actions,
> +                                  struct lflow_ref *lflow_ref)
>  {
>      int gw_mtu = smap_get_int(&op->nbrp->options, "gateway_mtu", 0);
>      if (gw_mtu <= 0) {
> @@ -13208,12 +13454,13 @@ build_check_pkt_len_flows_for_lrp(struct
ovn_port *op,
>      ds_clear(match);
>      ds_put_format(match, "outport == %s", op->json_key);
>      build_gateway_mtu_flow(lflows, op, S_ROUTER_IN_CHK_PKT_LEN, 50, 55,
> -                           match, actions, &op->nbrp->header_, "next;");
> +                           match, actions, &op->nbrp->header_,
> +                           lflow_ref, "next;");
>
>      /* ingress traffic */
>      build_icmperr_pkt_big_flows(op, gw_mtu, lflows, meter_groups,
>                                  match, actions, S_ROUTER_IN_IP_INPUT,
> -                                NULL);
> +                                NULL, lflow_ref);
>
>      for (size_t i = 0; i < op->od->nbr->n_ports; i++) {
>          struct ovn_port *rp = ovn_port_find(lr_ports,
> @@ -13225,7 +13472,7 @@ build_check_pkt_len_flows_for_lrp(struct ovn_port
*op,
>          /* egress traffic */
>          build_icmperr_pkt_big_flows(rp, gw_mtu, lflows, meter_groups,
>                                      match, actions,
S_ROUTER_IN_LARGER_PKTS,
> -                                    op);
> +                                    op, lflow_ref);
>      }
>  }
>
> @@ -13247,15 +13494,16 @@ build_check_pkt_len_flows_for_lrouter(
>          struct ovn_datapath *od, struct lflow_table *lflows,
>          const struct hmap *lr_ports,
>          struct ds *match, struct ds *actions,
> -        const struct shash *meter_groups)
> +        const struct shash *meter_groups,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
>
>      /* Packets are allowed by default. */
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_CHK_PKT_LEN, 0, "1",
> -                  "next;");
> +                  "next;", lflow_ref);
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_LARGER_PKTS, 0, "1",
> -                  "next;");
> +                  "next;", lflow_ref);
>
>      for (size_t i = 0; i < od->nbr->n_ports; i++) {
>          struct ovn_port *rp = ovn_port_find(lr_ports,
> @@ -13264,7 +13512,7 @@ build_check_pkt_len_flows_for_lrouter(
>              continue;
>          }
>          build_check_pkt_len_flows_for_lrp(rp, lflows, lr_ports,
meter_groups,
> -                                          match, actions);
> +                                          match, actions, lflow_ref);
>      }
>  }
>
> @@ -13272,7 +13520,8 @@ build_check_pkt_len_flows_for_lrouter(
>  static void
>  build_gateway_redirect_flows_for_lrouter(
>          struct ovn_datapath *od, struct lflow_table *lflows,
> -        struct ds *match, struct ds *actions)
> +        struct ds *match, struct ds *actions,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
>      for (size_t i = 0; i < od->n_l3dgw_ports; i++) {
> @@ -13305,18 +13554,20 @@ build_gateway_redirect_flows_for_lrouter(
>                        od->l3dgw_ports[i]->cr_port->json_key);
>          ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50,
>                                  ds_cstr(match), ds_cstr(actions),
> -                                stage_hint);
> +                                stage_hint, lflow_ref);
>      }
>
>      /* Packets are allowed by default. */
> -    ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 0, "1", "next;");
> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 0, "1", "next;",
> +                  lflow_ref);
>  }
>
>  /* Logical router ingress table GW_REDIRECT: Gateway redirect. */
>  static void
>  build_lr_gateway_redirect_flows_for_nats(
>          const struct ovn_datapath *od, const struct lr_nat_record
*lrnat_rec,
> -        struct lflow_table *lflows, struct ds *match, struct ds *actions)
> +        struct lflow_table *lflows, struct ds *match, struct ds *actions,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
>      for (size_t i = 0; i < od->n_l3dgw_ports; i++) {
> @@ -13357,21 +13608,23 @@ build_lr_gateway_redirect_flows_for_nats(
>              if (nat->nb->allowed_ext_ips) {
>                  ovn_lflow_add_with_hint(lflows, od,
S_ROUTER_IN_GW_REDIRECT,
>                                          75, ds_cstr(&match_ext),
> -                                        ds_cstr(actions), stage_hint);
> +                                        ds_cstr(actions), stage_hint,
> +                                        lflow_ref);
>                  if (add_def_flow) {
>                      ds_clear(&match_ext);
>                      ds_put_format(&match_ext, "ip && ip%s.dst == %s",
>                                    nat_entry_is_v6(nat) ? "6" : "4",
>                                    nat->nb->external_ip);
>                      ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT,
70,
> -                                  ds_cstr(&match_ext),
debug_drop_action());
> +                                  ds_cstr(&match_ext),
debug_drop_action(),
> +                                  lflow_ref);
>                      add_def_flow = false;
>                  }
>              } else if (nat->nb->exempted_ext_ips) {
>                  ovn_lflow_add_with_hint(lflows, od,
S_ROUTER_IN_GW_REDIRECT,
>                                          75, ds_cstr(&match_ext),
>                                          debug_drop_action(),
> -                                        stage_hint);
> +                                        stage_hint, lflow_ref);
>              }
>              ds_destroy(&match_ext);
>          }
> @@ -13387,7 +13640,8 @@ static void
>  build_arp_request_flows_for_lrouter(
>          struct ovn_datapath *od, struct lflow_table *lflows,
>          struct ds *match, struct ds *actions,
> -        const struct shash *meter_groups)
> +        const struct shash *meter_groups,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
>      for (int i = 0; i < od->nbr->n_static_routes; i++) {
> @@ -13429,7 +13683,8 @@ build_arp_request_flows_for_lrouter(
>                                    copp_meter_get(COPP_ND_NS_RESOLVE,
>                                                   od->nbr->copp,
>                                                   meter_groups),
> -                                  &route->header_);
> +                                  &route->header_,
> +                                  lflow_ref);
>      }
>
>      ovn_lflow_metered(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100,
> @@ -13442,7 +13697,8 @@ build_arp_request_flows_for_lrouter(
>                        "output; "
>                        "};",
>                        copp_meter_get(COPP_ARP_RESOLVE, od->nbr->copp,
> -                                     meter_groups));
> +                                     meter_groups),
> +                      lflow_ref);
>      ovn_lflow_metered(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100,
>                        "eth.dst == 00:00:00:00:00:00 && ip6",
>                        "nd_ns { "
> @@ -13450,8 +13706,10 @@ build_arp_request_flows_for_lrouter(
>                        "output; "
>                        "};",
>                        copp_meter_get(COPP_ND_NS_RESOLVE, od->nbr->copp,
> -                                     meter_groups));
> -    ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1",
"output;");
> +                                     meter_groups),
> +                      lflow_ref);
> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1", "output;",
> +                  lflow_ref);
>  }
>
>  /* Logical router egress table DELIVERY: Delivery (priority 100-110).
> @@ -13464,7 +13722,8 @@ build_arp_request_flows_for_lrouter(
>  static void
>  build_egress_delivery_flows_for_lrouter_port(
>          struct ovn_port *op, struct lflow_table *lflows,
> -        struct ds *match, struct ds *actions)
> +        struct ds *match, struct ds *actions,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbrp);
>      if (!lrport_is_enabled(op->nbrp)) {
> @@ -13492,20 +13751,23 @@ build_egress_delivery_flows_for_lrouter_port(
>          ds_put_format(actions, "eth.src = %s; output;",
>                        op->lrp_networks.ea_s);
>          ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 110,
> -                      ds_cstr(match), ds_cstr(actions));
> +                      ds_cstr(match), ds_cstr(actions),
> +                      lflow_ref);
>      }
>
>      ds_clear(match);
>      ds_put_format(match, "outport == %s", op->json_key);
>      ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 100,
> -                  ds_cstr(match), "output;");
> +                  ds_cstr(match), "output;", lflow_ref);
>
> -    ovn_lflow_add_default_drop(lflows, op->od, S_ROUTER_OUT_DELIVERY);
> +    ovn_lflow_add_default_drop(lflows, op->od, S_ROUTER_OUT_DELIVERY,
> +                               lflow_ref);
>  }
>
>  static void
>  build_misc_local_traffic_drop_flows_for_lrouter(
> -        struct ovn_datapath *od, struct lflow_table *lflows)
> +        struct ovn_datapath *od, struct lflow_table *lflows,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
>      /* Allow IGMP and MLD packets (with TTL = 1) if the router is
> @@ -13513,9 +13775,11 @@ build_misc_local_traffic_drop_flows_for_lrouter(
>       */
>      if (od->mcast_info.rtr.flood_static) {
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 120,
> -                      "igmp && ip.ttl == 1", "next;");
> +                      "igmp && ip.ttl == 1", "next;",
> +                      lflow_ref);
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 120,
> -                      "(mldv1 || mldv2) && ip.ttl == 1", "next;");
> +                      "(mldv1 || mldv2) && ip.ttl == 1", "next;",
> +                      lflow_ref);
>      }
>
>      /* L3 admission control: drop multicast and broadcast source,
localhost
> @@ -13528,7 +13792,8 @@ build_misc_local_traffic_drop_flows_for_lrouter(
>                    "ip4.dst == 127.0.0.0/8 || "
>                    "ip4.src == 0.0.0.0/8 || "
>                    "ip4.dst == 0.0.0.0/8",
> -                  debug_drop_action());
> +                  debug_drop_action(),
> +                  lflow_ref);
>
>      /* Drop ARP packets (priority 85). ARP request packets for router's
own
>       * IPs are handled with priority-90 flows.
> @@ -13536,28 +13801,32 @@ build_misc_local_traffic_drop_flows_for_lrouter(
>       * IPs are handled with priority-90 flows.
>       */
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 85,
> -                  "arp || nd", debug_drop_action());
> +                  "arp || nd", debug_drop_action(),
> +                  lflow_ref);
>
>      /* Allow IPv6 multicast traffic that's supposed to reach the
>       * router pipeline (e.g., router solicitations).
>       */
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 84, "nd_rs || nd_ra",
> -                  "next;");
> +                  "next;", lflow_ref);
>
>      /* Drop other reserved multicast. */
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 83,
> -                  "ip6.mcast_rsvd", debug_drop_action());
> +                  "ip6.mcast_rsvd", debug_drop_action(),
> +                  lflow_ref);
>
>      /* Allow other multicast if relay enabled (priority 82). */
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 82,
>                    "ip4.mcast || ip6.mcast",
>                    (od->mcast_info.rtr.relay ? "next;" :
> -                                              debug_drop_action()));
> +                                              debug_drop_action()),
> +                  lflow_ref);
>
>      /* Drop Ethernet local broadcast.  By definition this traffic should
>       * not be forwarded.*/
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50,
> -                  "eth.bcast", debug_drop_action());
> +                  "eth.bcast", debug_drop_action(),
> +                  lflow_ref);
>
>      /* Avoid ICMP time exceeded for multicast, silent drop instead.
>       * See RFC1812 section 5.3.1:
> @@ -13574,21 +13843,25 @@ build_misc_local_traffic_drop_flows_for_lrouter(
>       * (priority-31 flows will send ICMP time exceeded) */
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 32,
>                    "ip.ttl == {0, 1} && !ip.later_frag && "
> -                  "(ip4.mcast || ip6.mcast)", debug_drop_action());
> +                  "(ip4.mcast || ip6.mcast)", debug_drop_action(),
> +                  lflow_ref);
>
>      /* TTL discard */
>      ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30,
> -                  "ip.ttl == {0, 1}", debug_drop_action());
> +                  "ip.ttl == {0, 1}", debug_drop_action(),
> +                  lflow_ref);
>
>      /* Pass other traffic not already handled to the next table for
>       * routing. */
> -    ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 0, "1", "next;");
> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 0, "1", "next;",
> +                  lflow_ref);
>  }
>
>  static void
>  build_dhcpv6_reply_flows_for_lrouter_port(
>          struct ovn_port *op, struct lflow_table *lflows,
> -        struct ds *match)
> +        struct ds *match,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbrp);
>      if (op->l3dgw_port) {
> @@ -13601,7 +13874,8 @@ build_dhcpv6_reply_flows_for_lrouter_port(
>                        op->lrp_networks.ipv6_addrs[i].addr_s);
>          ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
>                        ds_cstr(match),
> -                      "reg0 = 0; handle_dhcpv6_reply;");
> +                      "reg0 = 0; handle_dhcpv6_reply;",
> +                      lflow_ref);
>      }
>  }
>
> @@ -13609,7 +13883,8 @@ static void
>  build_ipv6_input_flows_for_lrouter_port(
>          struct ovn_port *op, struct lflow_table *lflows,
>          struct ds *match, struct ds *actions,
> -        const struct shash *meter_groups)
> +        const struct shash *meter_groups,
> +        struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbrp);
>      if (is_cr_port(op)) {
> @@ -13633,7 +13908,7 @@ build_ipv6_input_flows_for_lrouter_port(
>                      "next; ";
>          ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
>                                  ds_cstr(match), lrp_actions,
> -                                &op->nbrp->header_);
> +                                &op->nbrp->header_, lflow_ref);
>      }
>
>      /* ND reply.  These flows reply to ND solicitations for the
> @@ -13654,7 +13929,8 @@ build_ipv6_input_flows_for_lrouter_port(
>                                op->lrp_networks.ipv6_addrs[i].addr_s,
>                                op->lrp_networks.ipv6_addrs[i].sn_addr_s,
>                                REG_INPORT_ETH_ADDR, match, false, 90,
> -                              &op->nbrp->header_, lflows, meter_groups);
> +                              &op->nbrp->header_, lflows, meter_groups,
> +                              lflow_ref);
>      }
>
>      /* UDP/TCP/SCTP port unreachable */
> @@ -13674,7 +13950,8 @@ build_ipv6_input_flows_for_lrouter_port(
>                                            COPP_TCP_RESET,
>                                            op->od->nbr->copp,
>                                            meter_groups),
> -                                      &op->nbrp->header_);
> +                                      &op->nbrp->header_,
> +                                      lflow_ref);
>
>              ds_clear(match);
>              ds_put_format(match,
> @@ -13690,7 +13967,8 @@ build_ipv6_input_flows_for_lrouter_port(
>                                            COPP_TCP_RESET,
>                                            op->od->nbr->copp,
>                                            meter_groups),
> -                                      &op->nbrp->header_);
> +                                      &op->nbrp->header_,
> +                                      lflow_ref);
>
>              ds_clear(match);
>              ds_put_format(match,
> @@ -13709,7 +13987,8 @@ build_ipv6_input_flows_for_lrouter_port(
>                                            COPP_ICMP6_ERR,
>                                            op->od->nbr->copp,
>                                            meter_groups),
> -                                      &op->nbrp->header_);
> +                                      &op->nbrp->header_,
> +                                      lflow_ref);
>
>              ds_clear(match);
>              ds_put_format(match,
> @@ -13728,7 +14007,8 @@ build_ipv6_input_flows_for_lrouter_port(
>                                            COPP_ICMP6_ERR,
>                                            op->od->nbr->copp,
>                                            meter_groups),
> -                                      &op->nbrp->header_);
> +                                      &op->nbrp->header_,
> +                                      lflow_ref);
>          }
>      }
>
> @@ -13768,7 +14048,7 @@ build_ipv6_input_flows_for_lrouter_port(
>                  31, ds_cstr(match), ds_cstr(actions), NULL,
>                  copp_meter_get(COPP_ICMP6_ERR, op->od->nbr->copp,
>                                 meter_groups),
> -                &op->nbrp->header_);
> +                &op->nbrp->header_, lflow_ref);
>      }
>      ds_destroy(&ip_ds);
>  }
> @@ -13777,7 +14057,8 @@ static void
>  build_lrouter_arp_nd_for_datapath(const struct ovn_datapath *od,
>                                    const struct lr_nat_record *lrnat_rec,
>                                    struct lflow_table *lflows,
> -                                  const struct shash *meter_groups)
> +                                  const struct shash *meter_groups,
> +                                  struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(od->nbr);
>      if (!od->nbr->n_nat) {
> @@ -13806,7 +14087,8 @@ build_lrouter_arp_nd_for_datapath(const struct
ovn_datapath *od,
>          if (!strcmp(nat_entry->nb->type, "snat")) {
>              continue;
>          }
> -        build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows,
meter_groups);
> +        build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows,
meter_groups,
> +                                      lflow_ref);
>      }
>
>      /* Now handle SNAT entries too, one per unique SNAT IP. */
> @@ -13821,7 +14103,8 @@ build_lrouter_arp_nd_for_datapath(const struct
ovn_datapath *od,
>          struct ovn_nat *nat_entry =
>              CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries),
>                           struct ovn_nat, ext_addr_list_node);
> -        build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows,
meter_groups);
> +        build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows,
meter_groups,
> +                                      lflow_ref);
>      }
>  }
>
> @@ -13830,7 +14113,8 @@ static void
>  build_lrouter_ipv4_ip_input(struct ovn_port *op,
>                              struct lflow_table *lflows,
>                              struct ds *match, struct ds *actions,
> -                            const struct shash *meter_groups)
> +                            const struct shash *meter_groups,
> +                            struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbrp);
>      /* No ingress packets are accepted on a chassisredirect
> @@ -13848,7 +14132,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
>          ds_put_cstr(match, " && "REGBIT_EGRESS_LOOPBACK" == 0");
>          ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
100,
>                                  ds_cstr(match), debug_drop_action(),
> -                                &op->nbrp->header_);
> +                                &op->nbrp->header_, lflow_ref);
>
>          /* ICMP echo reply.  These flows reply to ICMP echo requests
>           * received for the router's IP address. Since packets only
> @@ -13867,11 +14151,11 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
>                        "next; ";
>          ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
>                                  ds_cstr(match), icmp_actions,
> -                                &op->nbrp->header_);
> +                                &op->nbrp->header_, lflow_ref);
>      }
>
>      /* BFD msg handling */
> -    build_lrouter_bfd_flows(lflows, op, meter_groups);
> +    build_lrouter_bfd_flows(lflows, op, meter_groups, lflow_ref);
>
>      /* ICMP time exceeded */
>      struct ds ip_ds = DS_EMPTY_INITIALIZER;
> @@ -13900,7 +14184,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
>                  31, ds_cstr(match), ds_cstr(actions), NULL,
>                  copp_meter_get(COPP_ICMP4_ERR, op->od->nbr->copp,
>                                 meter_groups),
> -                &op->nbrp->header_);
> +                &op->nbrp->header_, lflow_ref);
>
>      }
>      ds_destroy(&ip_ds);
> @@ -13950,7 +14234,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
>          build_lrouter_arp_flow(op->od, op,
>                                 op->lrp_networks.ipv4_addrs[i].addr_s,
>                                 REG_INPORT_ETH_ADDR, match, false, 90,
> -                               &op->nbrp->header_, lflows);
> +                               &op->nbrp->header_, lflows, lflow_ref);
>      }
>
>      if (!op->od->is_gw_router && !op->od->n_l3dgw_ports) {
> @@ -13973,7 +14257,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
>                                            COPP_ICMP4_ERR,
>                                            op->od->nbr->copp,
>                                            meter_groups),
> -                                      &op->nbrp->header_);
> +                                      &op->nbrp->header_,
> +                                      lflow_ref);
>
>              ds_clear(match);
>              ds_put_format(match,
> @@ -13989,7 +14274,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
>                                            COPP_TCP_RESET,
>                                            op->od->nbr->copp,
>                                            meter_groups),
> -                                      &op->nbrp->header_);
> +                                      &op->nbrp->header_,
> +                                      lflow_ref);
>
>              ds_clear(match);
>              ds_put_format(match,
> @@ -14005,7 +14291,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
>                                            COPP_TCP_RESET,
>                                            op->od->nbr->copp,
>                                            meter_groups),
> -                                      &op->nbrp->header_);
> +                                      &op->nbrp->header_,
> +                                      lflow_ref);
>
>              ds_clear(match);
>              ds_put_format(match,
> @@ -14024,7 +14311,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
>                                            COPP_ICMP4_ERR,
>                                            op->od->nbr->copp,
>                                            meter_groups),
> -                                      &op->nbrp->header_);
> +                                      &op->nbrp->header_,
> +                                      lflow_ref);
>          }
>      }
>  }
> @@ -14034,7 +14322,8 @@ static void
>  build_lrouter_ipv4_ip_input_for_lbnats(struct ovn_port *op,
>                              struct lflow_table *lflows,
>                              const struct lr_stateful_record *lr_sful_rec,
> -                            struct ds *match, const struct shash
*meter_groups)
> +                            struct ds *match, const struct shash
*meter_groups,
> +                            struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbrp);
>      /* No ingress packets are accepted on a chassisredirect
> @@ -14055,7 +14344,7 @@ build_lrouter_ipv4_ip_input_for_lbnats(struct
ovn_port *op,
>                                                     AF_INET);
>          build_lrouter_arp_flow(op->od, op, lb_ips_v4_as,
>                                 REG_INPORT_ETH_ADDR,
> -                               match, false, 90, NULL, lflows);
> +                               match, false, 90, NULL, lflows,
lflow_ref);
>          free(lb_ips_v4_as);
>      }
>
> @@ -14072,7 +14361,7 @@ build_lrouter_ipv4_ip_input_for_lbnats(struct
ovn_port *op,
>                                                     AF_INET6);
>          build_lrouter_nd_flow(op->od, op, "nd_na", lb_ips_v6_as, NULL,
>                                REG_INPORT_ETH_ADDR, match, false, 90,
> -                              NULL, lflows, meter_groups);
> +                              NULL, lflows, meter_groups, lflow_ref);
>          free(lb_ips_v6_as);
>      }
>
> @@ -14104,7 +14393,7 @@ build_lrouter_ipv4_ip_input_for_lbnats(struct
ovn_port *op,
>              continue;
>          }
>          build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows,
> -                                        meter_groups);
> +                                        meter_groups, lflow_ref);
>      }
>
>      /* Now handle SNAT entries too, one per unique SNAT IP. */
> @@ -14120,7 +14409,7 @@ build_lrouter_ipv4_ip_input_for_lbnats(struct
ovn_port *op,
>              CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries),
>                          struct ovn_nat, ext_addr_list_node);
>          build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows,
> -                                        meter_groups);
> +                                        meter_groups, lflow_ref);
>      }
>  }
>
> @@ -14156,7 +14445,8 @@ build_lrouter_in_unsnat_stateless_flow(struct
lflow_table *lflows,
>                                         const struct nbrec_nat *nat,
>                                         struct ds *match,
>                                         bool distributed_nat, bool is_v6,
> -                                       struct ovn_port *l3dgw_port)
> +                                       struct ovn_port *l3dgw_port,
> +                                       struct lflow_ref *lflow_ref)
>  {
>      if (strcmp(nat->type, "snat") && strcmp(nat->type, "dnat_and_snat"))
{
>          return;
> @@ -14169,7 +14459,7 @@ build_lrouter_in_unsnat_stateless_flow(struct
lflow_table *lflows,
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT,
>                              priority, ds_cstr(match), "next;",
> -                            &nat->header_);
> +                            &nat->header_, lflow_ref);
>  }
>
>  static void
> @@ -14177,7 +14467,8 @@ build_lrouter_in_unsnat_in_czone_flow(struct
lflow_table *lflows,
>                                        const struct ovn_datapath *od,
>                                        const struct nbrec_nat *nat,
>                                        struct ds *match, bool
distributed_nat,
> -                                      bool is_v6, struct ovn_port
*l3dgw_port)
> +                                      bool is_v6, struct ovn_port
*l3dgw_port,
> +                                      struct lflow_ref *lflow_ref)
>  {
>      if (strcmp(nat->type, "snat") && strcmp(nat->type, "dnat_and_snat"))
{
>          return;
> @@ -14195,7 +14486,7 @@ build_lrouter_in_unsnat_in_czone_flow(struct
lflow_table *lflows,
>      ds_put_cstr(match, " && flags.loopback == 0");
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT,
>                              100, ds_cstr(match), "ct_snat_in_czone;",
> -                            &nat->header_);
> +                            &nat->header_, lflow_ref);
>
>      ds_truncate(match, common_match_len);
>      /* Update common zone match for the hairpin traffic. */
> @@ -14203,7 +14494,7 @@ build_lrouter_in_unsnat_in_czone_flow(struct
lflow_table *lflows,
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT,
>                              100, ds_cstr(match), "ct_snat;",
> -                            &nat->header_);
> +                            &nat->header_, lflow_ref);
>  }
>
>  static void
> @@ -14211,7 +14502,8 @@ build_lrouter_in_unsnat_flow(struct lflow_table
*lflows,
>                               const struct ovn_datapath *od,
>                               const struct nbrec_nat *nat, struct ds
*match,
>                               bool distributed_nat, bool is_v6,
> -                             struct ovn_port *l3dgw_port)
> +                             struct ovn_port *l3dgw_port,
> +                             struct lflow_ref *lflow_ref)
>  {
>
>      if (strcmp(nat->type, "snat") && strcmp(nat->type, "dnat_and_snat"))
{
> @@ -14225,7 +14517,7 @@ build_lrouter_in_unsnat_flow(struct lflow_table
*lflows,
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT,
>                              priority, ds_cstr(match), "ct_snat;",
> -                            &nat->header_);
> +                            &nat->header_, lflow_ref);
>  }
>
>  static void
> @@ -14235,7 +14527,8 @@ build_lrouter_in_dnat_flow(struct lflow_table
*lflows,
>                             const struct nbrec_nat *nat, struct ds *match,
>                             struct ds *actions, bool distributed_nat,
>                             int cidr_bits, bool is_v6,
> -                           struct ovn_port *l3dgw_port, bool stateless)
> +                           struct ovn_port *l3dgw_port, bool stateless,
> +                           struct lflow_ref *lflow_ref)
>  {
>      /* Ingress DNAT table: Packets enter the pipeline with destination
>      * IP address that needs to be DNATted from a external IP address
> @@ -14281,7 +14574,8 @@ build_lrouter_in_dnat_flow(struct lflow_table
*lflows,
>
>      if (nat->allowed_ext_ips || nat->exempted_ext_ips) {
>          lrouter_nat_add_ext_ip_match(od, lflows, match, nat,
> -                                     is_v6, true, cidr_bits);
> +                                     is_v6, true, cidr_bits,
> +                                     lflow_ref);
>      }
>
>      if (stateless) {
> @@ -14297,7 +14591,7 @@ build_lrouter_in_dnat_flow(struct lflow_table
*lflows,
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, 100,
>                              ds_cstr(match), ds_cstr(actions),
> -                            &nat->header_);
> +                            &nat->header_, lflow_ref);
>  }
>
>  static void
> @@ -14306,7 +14600,8 @@ build_lrouter_out_undnat_flow(struct lflow_table
*lflows,
>                                const struct nbrec_nat *nat, struct ds
*match,
>                                struct ds *actions, bool distributed_nat,
>                                struct eth_addr mac, bool is_v6,
> -                              struct ovn_port *l3dgw_port, bool
stateless)
> +                              struct ovn_port *l3dgw_port, bool
stateless,
> +                              struct lflow_ref *lflow_ref)
>  {
>      /* Egress UNDNAT table: It is for already established connections'
>      * reverse traffic. i.e., DNAT has already been done in ingress
> @@ -14348,7 +14643,7 @@ build_lrouter_out_undnat_flow(struct lflow_table
*lflows,
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 100,
>                              ds_cstr(match), ds_cstr(actions),
> -                            &nat->header_);
> +                            &nat->header_, lflow_ref);
>  }
>
>  static void
> @@ -14356,7 +14651,8 @@ build_lrouter_out_is_dnat_local(struct
lflow_table *lflows,
>                                  const struct ovn_datapath *od,
>                                  const struct nbrec_nat *nat, struct ds
*match,
>                                  struct ds *actions, bool distributed_nat,
> -                                bool is_v6, struct ovn_port *l3dgw_port)
> +                                bool is_v6, struct ovn_port *l3dgw_port,
> +                                struct lflow_ref *lflow_ref)
>  {
>      /* Note that this only applies for NAT on a distributed router.
>       */
> @@ -14379,7 +14675,7 @@ build_lrouter_out_is_dnat_local(struct
lflow_table *lflows,
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_CHECK_DNAT_LOCAL,
>                              50, ds_cstr(match), ds_cstr(actions),
> -                            &nat->header_);
> +                            &nat->header_, lflow_ref);
>  }
>
>  static void
> @@ -14387,7 +14683,8 @@ build_lrouter_out_snat_match(struct lflow_table
*lflows,
>                               const struct ovn_datapath *od,
>                               const struct nbrec_nat *nat, struct ds
*match,
>                               bool distributed_nat, int cidr_bits, bool
is_v6,
> -                             struct ovn_port *l3dgw_port)
> +                             struct ovn_port *l3dgw_port,
> +                             struct lflow_ref *lflow_ref)
>  {
>      ds_clear(match);
>
> @@ -14407,7 +14704,8 @@ build_lrouter_out_snat_match(struct lflow_table
*lflows,
>
>      if (nat->allowed_ext_ips || nat->exempted_ext_ips) {
>          lrouter_nat_add_ext_ip_match(od, lflows, match, nat,
> -                                     is_v6, false, cidr_bits);
> +                                     is_v6, false, cidr_bits,
> +                                     lflow_ref);
>      }
>  }
>
> @@ -14418,7 +14716,8 @@ build_lrouter_out_snat_stateless_flow(struct
lflow_table *lflows,
>                                        struct ds *match, struct ds
*actions,
>                                        bool distributed_nat,
>                                        struct eth_addr mac, int cidr_bits,
> -                                      bool is_v6, struct ovn_port
*l3dgw_port)
> +                                      bool is_v6, struct ovn_port
*l3dgw_port,
> +                                      struct lflow_ref *lflow_ref)
>  {
>      if (strcmp(nat->type, "snat") && strcmp(nat->type, "dnat_and_snat"))
{
>          return;
> @@ -14432,7 +14731,7 @@ build_lrouter_out_snat_stateless_flow(struct
lflow_table *lflows,
>      uint16_t priority = cidr_bits + 1;
>
>      build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat,
> -                                 cidr_bits, is_v6, l3dgw_port);
> +                                 cidr_bits, is_v6, l3dgw_port,
lflow_ref);
>
>      if (!od->is_gw_router) {
>          /* Distributed router. */
> @@ -14451,7 +14750,8 @@ build_lrouter_out_snat_stateless_flow(struct
lflow_table *lflows,
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_SNAT,
>                              priority, ds_cstr(match),
> -                            ds_cstr(actions), &nat->header_);
> +                            ds_cstr(actions), &nat->header_,
> +                            lflow_ref);
>  }
>
>  static void
> @@ -14461,7 +14761,8 @@ build_lrouter_out_snat_in_czone_flow(struct
lflow_table *lflows,
>                                       struct ds *match,
>                                       struct ds *actions, bool
distributed_nat,
>                                       struct eth_addr mac, int cidr_bits,
> -                                     bool is_v6, struct ovn_port
*l3dgw_port)
> +                                     bool is_v6, struct ovn_port
*l3dgw_port,
> +                                     struct lflow_ref *lflow_ref)
>  {
>      if (strcmp(nat->type, "snat") && strcmp(nat->type, "dnat_and_snat"))
{
>          return;
> @@ -14476,7 +14777,8 @@ build_lrouter_out_snat_in_czone_flow(struct
lflow_table *lflows,
>      struct ds zone_actions = DS_EMPTY_INITIALIZER;
>
>      build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat,
> -                                 cidr_bits, is_v6, l3dgw_port);
> +                                 cidr_bits, is_v6, l3dgw_port,
> +                                 lflow_ref);
>
>      if (od->n_l3dgw_ports) {
>          priority += 128;
> @@ -14505,13 +14807,15 @@ build_lrouter_out_snat_in_czone_flow(struct
lflow_table *lflows,
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_SNAT,
>                              priority, ds_cstr(match),
> -                            ds_cstr(actions), &nat->header_);
> +                            ds_cstr(actions), &nat->header_,
> +                            lflow_ref);
>
>      ds_put_cstr(match, " && "REGBIT_DST_NAT_IP_LOCAL" == 1");
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_SNAT,
>                              priority + 1, ds_cstr(match),
> -                            ds_cstr(&zone_actions), &nat->header_);
> +                            ds_cstr(&zone_actions), &nat->header_,
> +                            lflow_ref);
>
>      ds_destroy(&zone_actions);
>  }
> @@ -14522,7 +14826,8 @@ build_lrouter_out_snat_flow(struct lflow_table
*lflows,
>                              const struct nbrec_nat *nat, struct ds
*match,
>                              struct ds *actions, bool distributed_nat,
>                              struct eth_addr mac, int cidr_bits, bool
is_v6,
> -                            struct ovn_port *l3dgw_port)
> +                            struct ovn_port *l3dgw_port,
> +                            struct lflow_ref *lflow_ref)
>  {
>      if (strcmp(nat->type, "snat") && strcmp(nat->type, "dnat_and_snat"))
{
>          return;
> @@ -14536,7 +14841,7 @@ build_lrouter_out_snat_flow(struct lflow_table
*lflows,
>      uint16_t priority = cidr_bits + 1;
>
>      build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat,
> -                                 cidr_bits, is_v6, l3dgw_port);
> +                                 cidr_bits, is_v6, l3dgw_port,
lflow_ref);
>
>      if (!od->is_gw_router) {
>          /* Distributed router. */
> @@ -14559,7 +14864,8 @@ build_lrouter_out_snat_flow(struct lflow_table
*lflows,
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_SNAT,
>                              priority, ds_cstr(match),
> -                            ds_cstr(actions), &nat->header_);
> +                            ds_cstr(actions), &nat->header_,
> +                            lflow_ref);
>  }
>
>  static void
> @@ -14569,7 +14875,8 @@ build_lrouter_ingress_nat_check_pkt_len(struct
lflow_table *lflows,
>                                          bool is_v6, struct ds *match,
>                                          struct ds *actions, int mtu,
>                                          struct ovn_port *l3dgw_port,
> -                                        const struct shash *meter_groups)
> +                                        const struct shash *meter_groups,
> +                                        struct lflow_ref *lflow_ref)
>  {
>          ds_clear(match);
>          ds_put_format(match, "inport == %s && "REGBIT_PKT_LARGER
> @@ -14603,7 +14910,8 @@ build_lrouter_ingress_nat_check_pkt_len(struct
lflow_table *lflows,
>                                              COPP_ICMP4_ERR,
>                                              od->nbr->copp,
>                                              meter_groups),
> -                                      &nat->header_);
> +                                      &nat->header_,
> +                                      lflow_ref);
>          } else {
>              ds_put_format(match, " && ip6 && ip6.dst == %s",
nat->external_ip);
>              /* Set icmp6.frag_mtu to gw_mtu */
> @@ -14630,7 +14938,8 @@ build_lrouter_ingress_nat_check_pkt_len(struct
lflow_table *lflows,
>                                              COPP_ICMP6_ERR,
>                                              od->nbr->copp,
>                                              meter_groups),
> -                                      &nat->header_);
> +                                      &nat->header_,
> +                                      lflow_ref);
>          }
>  }
>
> @@ -14641,7 +14950,8 @@ build_lrouter_ingress_flow(struct lflow_table
*lflows,
>                             struct ds *actions, struct eth_addr mac,
>                             bool distributed_nat, bool is_v6,
>                             struct ovn_port *l3dgw_port,
> -                           const struct shash *meter_groups)
> +                           const struct shash *meter_groups,
> +                           struct lflow_ref *lflow_ref)
>  {
>      if (od->n_l3dgw_ports && !strcmp(nat->type, "snat")) {
>          ds_clear(match);
> @@ -14651,7 +14961,7 @@ build_lrouter_ingress_flow(struct lflow_table
*lflows,
>              is_v6 ? "ip6.src" : "ip4.src", nat->external_ip);
>          ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT,
>                                  120, ds_cstr(match), "next;",
> -                                &nat->header_);
> +                                &nat->header_, lflow_ref);
>      }
>      /* Logical router ingress table 0:
>      * For NAT on a distributed router, add rules allowing
> @@ -14675,12 +14985,14 @@ build_lrouter_ingress_flow(struct lflow_table
*lflows,
>          build_gateway_mtu_flow(lflows, l3dgw_port,
>                                 S_ROUTER_IN_ADMISSION, 50, 55,
>                                 match, actions, &nat->header_,
> +                               lflow_ref,
>                                 REG_INPORT_ETH_ADDR " = %s; next;",
>                                 l3dgw_port->lrp_networks.ea_s);
>          if (gw_mtu) {
>              build_lrouter_ingress_nat_check_pkt_len(lflows, nat, od,
is_v6,
>                                                      match, actions,
gw_mtu,
> -                                                    l3dgw_port,
meter_groups);
> +                                                    l3dgw_port,
meter_groups,
> +                                                    lflow_ref);
>          }
>      }
>  }
> @@ -14815,27 +15127,33 @@ lrouter_check_nat_entry(const struct
ovn_datapath *od,
>
>  /* NAT, Defrag and load balancing. */
>  static void build_lr_nat_defrag_and_lb_default_flows(struct ovn_datapath
*od,
> -                                                struct lflow_table
*lflows)
> +                                                struct lflow_table
*lflows,
> +                                                struct lflow_ref
*lflow_ref)
>  {
>      ovs_assert(od->nbr);
>
>      /* Packets are allowed by default. */
> -    ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 0, "1", "next;");
> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, 0, "1", "next;",
lflow_ref);
> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 0, "1", "next;",
lflow_ref);
>      ovn_lflow_add(lflows, od, S_ROUTER_OUT_CHECK_DNAT_LOCAL, 0, "1",
> -                  REGBIT_DST_NAT_IP_LOCAL" = 0; next;");
> -    ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_SNAT, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 0, "1", "next;");
> -    ovn_lflow_add(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 0, "1",
"next;");
> +                  REGBIT_DST_NAT_IP_LOCAL" = 0; next;", lflow_ref);
> +    ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 0, "1", "next;",
lflow_ref);
> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 0, "1", "next;",
lflow_ref);
> +    ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 0, "1", "next;",
lflow_ref);
> +    ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_SNAT, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 0, "1", "next;",
> +                  lflow_ref);
> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 0, "1", "next;",
> +                  lflow_ref);
>
>      /* Send the IPv6 NS packets to next table. When ovn-controller
>       * generates IPv6 NS (for the action - nd_ns{}), the injected
>       * packet would go through conntrack - which is not required. */
> -    ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 120, "nd_ns", "next;");
> +    ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 120, "nd_ns", "next;",
> +                  lflow_ref);
>  }
>
>  static void
> @@ -14845,7 +15163,8 @@ build_lrouter_nat_defrag_and_lb(
>      const struct hmap *ls_ports, const struct hmap *lr_ports,
>      struct ds *match, struct ds *actions,
>      const struct shash *meter_groups,
> -    const struct chassis_features *features)
> +    const struct chassis_features *features,
> +    struct lflow_ref *lflow_ref)
>  {
>      const struct ovn_datapath *od = lr_sful_rec->od;
>      ovs_assert(od->nbr);
> @@ -14870,16 +15189,18 @@ build_lrouter_nat_defrag_and_lb(
>
>          ds_put_format(match, " && %s.skip_snat == 1", ct_flag_reg);
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match),
> -                      "flags.skip_snat_for_lb = 1; ct_commit_nat;");
> +                      "flags.skip_snat_for_lb = 1; ct_commit_nat;",
> +                      lflow_ref);
>
>          ds_truncate(match, match_len);
>          ds_put_format(match, " && %s.force_snat == 1", ct_flag_reg);
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match),
> -                      "flags.force_snat_for_lb = 1; ct_commit_nat;");
> +                      "flags.force_snat_for_lb = 1; ct_commit_nat;",
> +                      lflow_ref);
>
>          ds_truncate(match, match_len);
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, ds_cstr(match),
> -                      "ct_commit_nat;");
> +                      "ct_commit_nat;", lflow_ref);
>      }
>
>      /* Ingress DNAT (Priority 50/70).
> @@ -14896,16 +15217,18 @@ build_lrouter_nat_defrag_and_lb(
>
>          ds_put_format(match, " && %s.skip_snat == 1", ct_flag_reg);
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match),
> -                      "flags.skip_snat_for_lb = 1; next;");
> +                      "flags.skip_snat_for_lb = 1; next;",
> +                      lflow_ref);
>
>          ds_truncate(match, match_len);
>          ds_put_format(match, " && %s.force_snat == 1", ct_flag_reg);
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match),
> -                      "flags.force_snat_for_lb = 1; next;");
> +                      "flags.force_snat_for_lb = 1; next;",
> +                      lflow_ref);
>
>          ds_truncate(match, match_len);
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, ds_cstr(match),
> -                      "next;");
> +                      "next;", lflow_ref);
>      }
>
>      /* If the router has load balancer or DNAT rules, re-circulate every
packet
> @@ -14920,11 +15243,14 @@ build_lrouter_nat_defrag_and_lb(
>      if (od->is_gw_router && (od->nbr->n_nat || lr_sful_rec->has_lb_vip))
{
>          /* Do not send ND or ICMP packets to connection tracking. */
>          ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100,
> -                      "nd || nd_rs || nd_ra", "next;");
> +                      "nd || nd_rs || nd_ra", "next;",
> +                      lflow_ref);
>          ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 50,
> -                      "ip", "flags.loopback = 1; ct_dnat;");
> +                      "ip", "flags.loopback = 1; ct_dnat;",
> +                      lflow_ref);
>          ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 50,
> -                      "ip && ct.new", "ct_commit { } ; next; ");
> +                      "ip && ct.new", "ct_commit { } ; next; ",
> +                      lflow_ref);
>      }
>
>      /* NAT rules are only valid on Gateway routers and routers with
> @@ -14973,19 +15299,20 @@ build_lrouter_nat_defrag_and_lb(
>          if (stateless) {
>              build_lrouter_in_unsnat_stateless_flow(lflows, od, nat,
match,
>                                                     distributed_nat,
is_v6,
> -                                                   l3dgw_port);
> +                                                   l3dgw_port,
lflow_ref);
>          } else if (lrouter_use_common_zone(od)) {
>              build_lrouter_in_unsnat_in_czone_flow(lflows, od, nat, match,
>                                                    distributed_nat, is_v6,
> -                                                  l3dgw_port);
> +                                                  l3dgw_port, lflow_ref);
>          } else {
>              build_lrouter_in_unsnat_flow(lflows, od, nat, match,
> -                                         distributed_nat, is_v6,
l3dgw_port);
> +                                         distributed_nat, is_v6,
l3dgw_port,
> +                                         lflow_ref);
>          }
>          /* S_ROUTER_IN_DNAT */
>          build_lrouter_in_dnat_flow(lflows, od, lrnat_rec, nat, match,
actions,
>                                     distributed_nat, cidr_bits, is_v6,
> -                                   l3dgw_port, stateless);
> +                                   l3dgw_port, stateless, lflow_ref);
>
>          /* ARP resolve for NAT IPs. */
>          if (od->is_gw_router) {
> @@ -15008,7 +15335,8 @@ build_lrouter_nat_defrag_and_lb(
>                                          S_ROUTER_IN_ARP_RESOLVE,
>                                          150, ds_cstr(match),
>                                          debug_drop_action(),
> -                                        &nat->header_);
> +                                        &nat->header_,
> +                                        lflow_ref);
>                  /* Now for packets coming from other (downlink) LRPs,
allow ARP
>                   * resolve for the NAT IP, so that such packets can be
>                   * forwarded for E/W NAT. */
> @@ -15027,7 +15355,8 @@ build_lrouter_nat_defrag_and_lb(
>                                          S_ROUTER_IN_ARP_RESOLVE,
>                                          100, ds_cstr(match),
>                                          ds_cstr(actions),
> -                                        &nat->header_);
> +                                        &nat->header_,
> +                                        lflow_ref);
>                  if (od->redirect_bridged && distributed_nat) {
>                      ds_clear(match);
>                      ds_put_format(
> @@ -15048,7 +15377,8 @@ build_lrouter_nat_defrag_and_lb(
>                      ovn_lflow_add_with_hint(lflows, od,
>                                              S_ROUTER_IN_ARP_RESOLVE, 90,
>                                              ds_cstr(match),
ds_cstr(actions),
> -                                            &nat->header_);
> +                                            &nat->header_,
> +                                            lflow_ref);
>                  }
>                  sset_add(&nat_entries, nat->external_ip);
>              }
> @@ -15058,13 +15388,13 @@ build_lrouter_nat_defrag_and_lb(
>              /* S_ROUTER_OUT_DNAT_LOCAL */
>              build_lrouter_out_is_dnat_local(lflows, od, nat, match,
actions,
>                                              distributed_nat, is_v6,
> -                                            l3dgw_port);
> +                                            l3dgw_port, lflow_ref);
>          }
>
>          /* S_ROUTER_OUT_UNDNAT */
>          build_lrouter_out_undnat_flow(lflows, od, nat, match, actions,
>                                        distributed_nat, mac, is_v6,
l3dgw_port,
> -                                      stateless);
> +                                      stateless, lflow_ref);
>          /* S_ROUTER_OUT_SNAT
>           * Egress SNAT table: Packets enter the egress pipeline with
>           * source ip address that needs to be SNATted to a external ip
> @@ -15073,21 +15403,22 @@ build_lrouter_nat_defrag_and_lb(
>              build_lrouter_out_snat_stateless_flow(lflows, od, nat, match,
>                                                    actions,
distributed_nat,
>                                                    mac, cidr_bits, is_v6,
> -                                                  l3dgw_port);
> +                                                  l3dgw_port, lflow_ref);
>          } else if (lrouter_use_common_zone(od)) {
>              build_lrouter_out_snat_in_czone_flow(lflows, od, nat, match,
>                                                   actions,
distributed_nat, mac,
> -                                                 cidr_bits, is_v6,
l3dgw_port);
> +                                                 cidr_bits, is_v6,
l3dgw_port,
> +                                                 lflow_ref);
>          } else {
>              build_lrouter_out_snat_flow(lflows, od, nat, match, actions,
>                                          distributed_nat, mac, cidr_bits,
is_v6,
> -                                        l3dgw_port);
> +                                        l3dgw_port, lflow_ref);
>          }
>
>          /* S_ROUTER_IN_ADMISSION - S_ROUTER_IN_IP_INPUT */
>          build_lrouter_ingress_flow(lflows, od, nat, match, actions, mac,
>                                     distributed_nat, is_v6, l3dgw_port,
> -                                   meter_groups);
> +                                   meter_groups, lflow_ref);
>
>          /* Ingress Gateway Redirect Table: For NAT on a distributed
>           * router, add flows that are specific to a NAT rule.  These
> @@ -15114,7 +15445,8 @@ build_lrouter_nat_defrag_and_lb(
>              if (op && op->nbsp && !strcmp(op->nbsp->type, "virtual")) {
>                  ovn_lflow_add_with_hint(lflows, od,
S_ROUTER_IN_GW_REDIRECT,
>                                          80, ds_cstr(match),
> -                                        debug_drop_action(),
&nat->header_);
> +                                        debug_drop_action(),
&nat->header_,
> +                                        lflow_ref);
>              }
>              ds_put_format(match, " && is_chassis_resident(\"%s\")",
>                            nat->logical_port);
> @@ -15124,7 +15456,8 @@ build_lrouter_nat_defrag_and_lb(
>                            nat->external_ip);
>              ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT,
>                                      100, ds_cstr(match),
> -                                    ds_cstr(actions), &nat->header_);
> +                                    ds_cstr(actions), &nat->header_,
> +                                    lflow_ref);
>          }
>
>          /* Egress Loopback table: For NAT on a distributed router.
> @@ -15165,7 +15498,7 @@ build_lrouter_nat_defrag_and_lb(
>                            ovn_stage_get_table(S_ROUTER_IN_ADMISSION));
>              ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_EGR_LOOP,
100,
>                                      ds_cstr(match), ds_cstr(actions),
> -                                    &nat->header_);
> +                                    &nat->header_, lflow_ref);
>          }
>      }
>
> @@ -15185,7 +15518,7 @@ build_lrouter_nat_defrag_and_lb(
>          ds_put_cstr(actions, REGBIT_DST_NAT_IP_LOCAL" = 1; next;");
>          ovn_lflow_add_with_hint(lflows, od,
S_ROUTER_OUT_CHECK_DNAT_LOCAL,
>                                  50, ds_cstr(match), ds_cstr(actions),
> -                                &od->nbr->header_);
> +                                &od->nbr->header_, lflow_ref);
>
>      }
>
> @@ -15195,22 +15528,24 @@ build_lrouter_nat_defrag_and_lb(
>              if (lrnat_rec->dnat_force_snat_addrs.n_ipv4_addrs) {
>                  build_lrouter_force_snat_flows(lflows, od, "4",
>
 lrnat_rec->dnat_force_snat_addrs.ipv4_addrs[0].addr_s,
> -                    "dnat");
> +                    "dnat", lflow_ref);
>              }
>              if (lrnat_rec->dnat_force_snat_addrs.n_ipv6_addrs) {
>                  build_lrouter_force_snat_flows(lflows, od, "6",
>
 lrnat_rec->dnat_force_snat_addrs.ipv6_addrs[0].addr_s,
> -                    "dnat");
> +                    "dnat", lflow_ref);
>              }
>          }
>          if (lb_force_snat_ip) {
>              if (lrnat_rec->lb_force_snat_addrs.n_ipv4_addrs) {
>                  build_lrouter_force_snat_flows(lflows, od, "4",
> -                    lrnat_rec->lb_force_snat_addrs.ipv4_addrs[0].addr_s,
"lb");
> +                    lrnat_rec->lb_force_snat_addrs.ipv4_addrs[0].addr_s,
"lb",
> +                    lflow_ref);
>              }
>              if (lrnat_rec->lb_force_snat_addrs.n_ipv6_addrs) {
>                  build_lrouter_force_snat_flows(lflows, od, "6",
> -                    lrnat_rec->lb_force_snat_addrs.ipv6_addrs[0].addr_s,
"lb");
> +                    lrnat_rec->lb_force_snat_addrs.ipv6_addrs[0].addr_s,
"lb",
> +                    lflow_ref);
>              }
>          }
>      }
> @@ -15248,7 +15583,8 @@ build_lbnat_lflows_iterate_by_lsp(struct ovn_port
*op,
>                                    const struct hmap *lr_ports,
>                                    struct ds *match,
>                                    struct ds *actions,
> -                                  struct lflow_table *lflows)
> +                                  struct lflow_table *lflows,
> +                                  struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbsp);
>
> @@ -15263,7 +15599,7 @@ build_lbnat_lflows_iterate_by_lsp(struct ovn_port
*op,
>
>      build_lsp_lflows_for_lbnats(op, op->peer, lr_sful_rec,
>                                  lr_sful_table, lr_ports, lflows,
> -                                match, actions, op->stateful_lflow_ref);
> +                                match, actions, lflow_ref);
>  }
>
>  static void
> @@ -15271,7 +15607,8 @@ build_lrp_lflows_for_lbnats(struct ovn_port *op,
>                              const struct lr_stateful_record *lr_sful_rec,
>                              const struct shash *meter_groups,
>                              struct ds *match, struct ds *actions,
> -                            struct lflow_table *lflows)
> +                            struct lflow_table *lflows,
> +                            struct lflow_ref *lflow_ref)
>  {
>      /* Drop IP traffic destined to router owned IPs except if the IP is
>       * also a SNAT IP. Those are dropped later, in stage
> @@ -15284,7 +15621,8 @@ build_lrp_lflows_for_lbnats(struct ovn_port *op,
>       */
>      if (!lr_sful_rec->lrnat_rec->lb_force_snat_router_ip) {
>          build_lrouter_drop_own_dest(op, lr_sful_rec,
> -                                    S_ROUTER_IN_IP_INPUT, 60, false,
lflows);
> +                                    S_ROUTER_IN_IP_INPUT, 60, false,
> +                                    lflows, lflow_ref);
>      }
>
>      /* Drop IP traffic destined to router owned IPs. Part of it is
dropped
> @@ -15294,12 +15632,14 @@ build_lrp_lflows_for_lbnats(struct ovn_port *op,
>       * Priority 2.
>       */
>      build_lrouter_drop_own_dest(op, lr_sful_rec,
> -                                S_ROUTER_IN_ARP_RESOLVE, 2, true,
lflows);
> +                                S_ROUTER_IN_ARP_RESOLVE, 2, true,
> +                                lflows, lflow_ref);
>
>      build_lrouter_ipv4_ip_input_for_lbnats(op, lflows, lr_sful_rec,
> -                                           match, meter_groups);
> +                                           match, meter_groups,
> +                                           lflow_ref);
>      build_lrouter_force_snat_flows_op(op, lr_sful_rec->lrnat_rec, lflows,
> -                                      match, actions);
> +                                      match, actions, lflow_ref);
>  }
>
>  static void
> @@ -15308,7 +15648,8 @@ build_lbnat_lflows_iterate_by_lrp(struct ovn_port
*op,
>                                    const struct shash *meter_groups,
>                                    struct ds *match,
>                                    struct ds *actions,
> -                                  struct lflow_table *lflows)
> +                                  struct lflow_table *lflows,
> +                                  struct lflow_ref *lflow_ref)
>  {
>      ovs_assert(op->nbrp);
>
> @@ -15318,7 +15659,7 @@ build_lbnat_lflows_iterate_by_lrp(struct ovn_port
*op,
>      ovs_assert(lr_sful_rec);
>
>      build_lrp_lflows_for_lbnats(op, lr_sful_rec, meter_groups, match,
> -                                actions, lflows);
> +                                actions, lflows, lflow_ref);
>  }
>
>  static void
> @@ -15332,13 +15673,16 @@ build_lr_stateful_flows(const struct
lr_stateful_record *lr_sful_rec,
>                          const struct chassis_features *features)
>  {
>      build_lrouter_nat_defrag_and_lb(lr_sful_rec, lflows, ls_ports,
lr_ports,
> -                                    match, actions, meter_groups,
features);
> +                                    match, actions, meter_groups,
features,
> +                                    NULL);
>      build_lr_gateway_redirect_flows_for_nats(lr_sful_rec->od,
>                                               lr_sful_rec->lrnat_rec,
lflows,
> -                                             match, actions);
> +                                             match, actions,
> +                                             NULL);
>      build_lrouter_arp_nd_for_datapath(lr_sful_rec->od,
>                                        lr_sful_rec->lrnat_rec, lflows,
> -                                      meter_groups);
> +                                      meter_groups,
> +                                      NULL);
>  }
>
>  static void
> @@ -15350,11 +15694,13 @@ build_ls_stateful_flows(const struct
ls_stateful_record *ls_stateful_rec,
>  {
>      ovs_assert(ls_stateful_rec->od);
>
> -    build_ls_stateful_rec_pre_acls(ls_stateful_rec, ls_pgs, lflows);
> -    build_ls_stateful_rec_pre_lb(ls_stateful_rec, lflows);
> -    build_acl_hints(ls_stateful_rec, features, lflows);
> -    build_acls(ls_stateful_rec, features, lflows, ls_pgs, meter_groups);
> -    build_lb_hairpin(ls_stateful_rec, lflows);
> +    build_ls_stateful_rec_pre_acls(ls_stateful_rec, ls_pgs, lflows,
> +                                   NULL);
> +    build_ls_stateful_rec_pre_lb(ls_stateful_rec, lflows, NULL);
> +    build_acl_hints(ls_stateful_rec, features, lflows, NULL);
> +    build_acls(ls_stateful_rec, features, lflows, ls_pgs, meter_groups,
> +               NULL);
> +    build_lb_hairpin(ls_stateful_rec, lflows, NULL);
>  }
>
>  struct lswitch_flow_build_info {
> @@ -15390,19 +15736,20 @@ build_lswitch_and_lrouter_iterate_by_ls(struct
ovn_datapath *od,
>  {
>      ovs_assert(od->nbs);
>      build_lswitch_lflows_pre_acl_and_acl(od, lsi->features, lsi->lflows,
> -                                         lsi->meter_groups);
> -
> -    build_fwd_group_lflows(od, lsi->lflows);
> -    build_lswitch_lflows_admission_control(od, lsi->lflows);
> -    build_lswitch_learn_fdb_od(od, lsi->lflows);
> -    build_lswitch_arp_nd_responder_default(od, lsi->lflows);
> -    build_lswitch_dns_lookup_and_response(od, lsi->lflows,
lsi->meter_groups);
> -    build_lswitch_dhcp_and_dns_defaults(od, lsi->lflows);
> +                                         lsi->meter_groups, NULL);
> +
> +    build_fwd_group_lflows(od, lsi->lflows, NULL);
> +    build_lswitch_lflows_admission_control(od, lsi->lflows, NULL);
> +    build_lswitch_learn_fdb_od(od, lsi->lflows, NULL);
> +    build_lswitch_arp_nd_responder_default(od, lsi->lflows, NULL);
> +    build_lswitch_dns_lookup_and_response(od, lsi->lflows,
lsi->meter_groups,
> +                                          NULL);
> +    build_lswitch_dhcp_and_dns_defaults(od, lsi->lflows, NULL);
>      build_lswitch_destination_lookup_bmcast(od, lsi->lflows,
&lsi->actions,
> -                                            lsi->meter_groups);
> -    build_lswitch_output_port_sec_od(od, lsi->lflows);
> -    build_lswitch_lb_affinity_default_flows(od, lsi->lflows);
> -    build_lswitch_lflows_l2_unknown(od, lsi->lflows);
> +                                            lsi->meter_groups, NULL);
> +    build_lswitch_output_port_sec_od(od, lsi->lflows, NULL);
> +    build_lswitch_lb_affinity_default_flows(od, lsi->lflows, NULL);
> +    build_lswitch_lflows_l2_unknown(od, lsi->lflows, NULL);
>  }
>
>  /* Helper function to combine all lflow generation which is iterated by
> @@ -15413,29 +15760,34 @@ build_lswitch_and_lrouter_iterate_by_lr(struct
ovn_datapath *od,
>                                          struct lswitch_flow_build_info
*lsi)
>  {
>      ovs_assert(od->nbr);
> -    build_adm_ctrl_flows_for_lrouter(od, lsi->lflows);
> +    build_adm_ctrl_flows_for_lrouter(od, lsi->lflows, NULL);
>      build_neigh_learning_flows_for_lrouter(od, lsi->lflows, &lsi->match,
> -                                           &lsi->actions,
lsi->meter_groups);
> -    build_ND_RA_flows_for_lrouter(od, lsi->lflows);
> -    build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows);
> +                                           &lsi->actions,
> +                                           lsi->meter_groups, NULL);
> +    build_ND_RA_flows_for_lrouter(od, lsi->lflows, NULL);
> +    build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows, NULL);
>      build_static_route_flows_for_lrouter(od, lsi->features,
>                                           lsi->lflows, lsi->lr_ports,
> -                                         lsi->bfd_connections);
> +                                         lsi->bfd_connections,
> +                                         NULL);
>      build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match,
> -                                         &lsi->actions);
> -    build_ingress_policy_flows_for_lrouter(od, lsi->lflows,
lsi->lr_ports);
> -    build_arp_resolve_flows_for_lrouter(od, lsi->lflows);
> +                                         &lsi->actions, NULL);
> +    build_ingress_policy_flows_for_lrouter(od, lsi->lflows,
lsi->lr_ports,
> +                                           NULL);
> +    build_arp_resolve_flows_for_lrouter(od, lsi->lflows, NULL);
>      build_check_pkt_len_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports,
>                                            &lsi->match, &lsi->actions,
> -                                          lsi->meter_groups);
> +                                          lsi->meter_groups, NULL);
>      build_gateway_redirect_flows_for_lrouter(od, lsi->lflows,
&lsi->match,
> -                                             &lsi->actions);
> +                                             &lsi->actions, NULL);
>      build_arp_request_flows_for_lrouter(od, lsi->lflows, &lsi->match,
> -                                        &lsi->actions,
lsi->meter_groups);
> -    build_misc_local_traffic_drop_flows_for_lrouter(od, lsi->lflows);
> +                                        &lsi->actions,
> +                                        lsi->meter_groups,
> +                                        NULL);
> +    build_misc_local_traffic_drop_flows_for_lrouter(od, lsi->lflows,
NULL);
>
> -    build_lr_nat_defrag_and_lb_default_flows(od, lsi->lflows);
> -    build_lrouter_lb_affinity_default_flows(od, lsi->lflows);
> +    build_lr_nat_defrag_and_lb_default_flows(od, lsi->lflows, NULL);
> +    build_lrouter_lb_affinity_default_flows(od, lsi->lflows, NULL);
>  }
>
>  /* Helper function to combine all lflow generation which is iterated by
logical
> @@ -15477,22 +15829,26 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct
ovn_port *op,
>      ovs_assert(op->nbrp);
>
>      build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
> -                                          &lsi->actions);
> +                                          &lsi->actions, op->lflow_ref);
>      build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows,
&lsi->match,
> -                                                &lsi->actions);
> -    build_ip_routing_flows_for_lrp(op, lsi->lflows);
> +                                                &lsi->actions,
op->lflow_ref);
> +    build_ip_routing_flows_for_lrp(op, lsi->lflows, op->lflow_ref);
>      build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
> -                                       &lsi->actions, lsi->meter_groups);
> +                                       &lsi->actions, lsi->meter_groups,
> +                                       op->lflow_ref);
>      build_arp_resolve_flows_for_lrp(op, lsi->lflows,
> -                                    &lsi->match, &lsi->actions);
> +                                    &lsi->match, &lsi->actions,
op->lflow_ref);
>      build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows,
&lsi->match,
> -                                                 &lsi->actions);
> -    build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows,
&lsi->match);
> +                                                 &lsi->actions,
> +                                                 op->lflow_ref);
> +    build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows,
&lsi->match,
> +                                              op->lflow_ref);
>      build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows,
>                                              &lsi->match, &lsi->actions,
> -                                            lsi->meter_groups);
> +                                            lsi->meter_groups,
> +                                            op->lflow_ref);
>      build_lrouter_ipv4_ip_input(op, lsi->lflows, &lsi->match,
&lsi->actions,
> -                                lsi->meter_groups);
> +                                lsi->meter_groups, op->lflow_ref);
>  }
>
>  static void *
> @@ -15560,7 +15916,8 @@ build_lflows_thread(void *arg)
>                                                        lsi->lr_ports,
>                                                        &lsi->match,
>                                                        &lsi->actions,
> -                                                      lsi->lflows);
> +                                                      lsi->lflows,
> +
 op->stateful_lflow_ref);
>                  }
>              }
>              for (bnum = control->id;
> @@ -15577,7 +15934,8 @@ build_lflows_thread(void *arg)
>                                                        lsi->meter_groups,
>                                                        &lsi->match,
>                                                        &lsi->actions,
> -                                                      lsi->lflows);
> +                                                      lsi->lflows,
> +
 op->stateful_lflow_ref);
>                  }
>              }
>              for (bnum = control->id;
> @@ -15593,23 +15951,27 @@ build_lflows_thread(void *arg)
>                                                           lsi->ls_ports,
>                                                           lsi->lflows,
>                                                           &lsi->match,
> -                                                         &lsi->actions);
> +                                                         &lsi->actions,
> +                                                         NULL);
>                      build_lrouter_defrag_flows_for_lb(lb_dps,
lsi->lflows,
>                                                        lsi->lr_datapaths,
> -                                                      &lsi->match);
> +                                                      &lsi->match,
> +                                                      NULL);
>                      build_lrouter_flows_for_lb(lb_dps, lsi->lflows,
>                                                 lsi->meter_groups,
>                                                 lsi->lr_datapaths,
>                                                 lsi->lr_sful_table,
>                                                 lsi->features,
>                                                 lsi->svc_monitor_map,
> -                                               &lsi->match,
&lsi->actions);
> +                                               &lsi->match,
&lsi->actions,
> +                                               NULL);
>                      build_lswitch_flows_for_lb(lb_dps, lsi->lflows,
>                                                 lsi->meter_groups,
>                                                 lsi->ls_datapaths,
>                                                 lsi->features,
>                                                 lsi->svc_monitor_map,
> -                                               &lsi->match,
&lsi->actions);
> +                                               &lsi->match,
&lsi->actions,
> +                                               NULL);
>                  }
>              }
>              for (bnum = control->id;
> @@ -15654,7 +16016,7 @@ build_lflows_thread(void *arg)
>                      }
>                      build_lswitch_ip_mcast_igmp_mld(igmp_group,
lsi->lflows,
>                                                      &lsi->match,
> -                                                    &lsi->actions);
> +                                                    &lsi->actions, NULL);
>                  }
>              }
>          }
> @@ -15807,7 +16169,8 @@ build_lswitch_and_lrouter_flows(const struct
ovn_datapaths *ls_datapaths,
>                                                       lsi.lflows);
>              build_lbnat_lflows_iterate_by_lsp(op, lsi.lr_sful_table,
lsi.lr_ports,
>                                                &lsi.match, &lsi.actions,
> -                                              lsi.lflows);
> +                                              lsi.lflows,
> +                                              op->stateful_lflow_ref);
>          }
>          HMAP_FOR_EACH (op, key_node, lr_ports) {
>              build_lswitch_and_lrouter_iterate_by_lrp(op, &lsi);
> @@ -15815,24 +16178,29 @@ build_lswitch_and_lrouter_flows(const struct
ovn_datapaths *ls_datapaths,
>                                                lsi.meter_groups,
>                                                &lsi.match,
>                                                &lsi.actions,
> -                                              lsi.lflows);
> +                                              lsi.lflows,
> +                                              op->stateful_lflow_ref);
>          }
>          stopwatch_stop(LFLOWS_PORTS_STOPWATCH_NAME, time_msec());
>          stopwatch_start(LFLOWS_LBS_STOPWATCH_NAME, time_msec());
>          HMAP_FOR_EACH (lb_dps, hmap_node, lb_dps_map) {
>              build_lswitch_arp_nd_service_monitor(lb_dps->lb,
lsi.ls_ports,
>                                                   lsi.lflows,
&lsi.actions,
> -                                                 &lsi.match);
> +                                                 &lsi.match,
> +                                                 NULL);
>              build_lrouter_defrag_flows_for_lb(lb_dps, lsi.lflows,
> -                                              lsi.lr_datapaths,
&lsi.match);
> +                                              lsi.lr_datapaths,
&lsi.match,
> +                                              NULL);
>              build_lrouter_flows_for_lb(lb_dps, lsi.lflows,
lsi.meter_groups,
>                                         lsi.lr_datapaths,
lsi.lr_sful_table,
>                                         lsi.features, lsi.svc_monitor_map,
> -                                       &lsi.match, &lsi.actions);
> +                                       &lsi.match, &lsi.actions,
> +                                       NULL);
>              build_lswitch_flows_for_lb(lb_dps, lsi.lflows,
lsi.meter_groups,
>                                         lsi.ls_datapaths, lsi.features,
>                                         lsi.svc_monitor_map,
> -                                       &lsi.match, &lsi.actions);
> +                                       &lsi.match, &lsi.actions,
> +                                       NULL);
>          }
>          stopwatch_stop(LFLOWS_LBS_STOPWATCH_NAME, time_msec());
>
> @@ -15854,7 +16222,8 @@ build_lswitch_and_lrouter_flows(const struct
ovn_datapaths *ls_datapaths,
>              build_lswitch_ip_mcast_igmp_mld(igmp_group,
>                                              lsi.lflows,
>                                              &lsi.actions,
> -                                            &lsi.match);
> +                                            &lsi.match,
> +                                            NULL);
>          }
>          stopwatch_stop(LFLOWS_IGMP_STOPWATCH_NAME, time_msec());
>
> --
> 2.41.0
>
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
diff mbox series

Patch

diff --git a/northd/lflow-mgr.h b/northd/lflow-mgr.h
index 7809c939e6..02b74aa131 100644
--- a/northd/lflow-mgr.h
+++ b/northd/lflow-mgr.h
@@ -89,41 +89,27 @@  void lflow_table_add_lflow_default_drop(struct lflow_table *,
 /* Adds a row with the specified contents to the Logical_Flow table. */
 #define ovn_lflow_add_with_hint__(LFLOW_TABLE, OD, STAGE, PRIORITY, MATCH, \
                                   ACTIONS, IN_OUT_PORT, CTRL_METER, \
-                                  STAGE_HINT) \
-    lflow_table_add_lflow(LFLOW_TABLE, OD, NULL, 0, STAGE, PRIORITY, MATCH, \
-                          ACTIONS, IN_OUT_PORT, CTRL_METER, STAGE_HINT, \
-                          OVS_SOURCE_LOCATOR, NULL)
-
-#define ovn_lflow_add_with_lflow_ref_hint__(LFLOW_TABLE, OD, STAGE, PRIORITY, \
-                                            MATCH, ACTIONS, IN_OUT_PORT, \
-                                            CTRL_METER, STAGE_HINT, LFLOW_REF)\
+                                  STAGE_HINT, LFLOW_REF) \
     lflow_table_add_lflow(LFLOW_TABLE, OD, NULL, 0, STAGE, PRIORITY, MATCH, \
                           ACTIONS, IN_OUT_PORT, CTRL_METER, STAGE_HINT, \
                           OVS_SOURCE_LOCATOR, LFLOW_REF)
 
 #define ovn_lflow_add_with_hint(LFLOW_TABLE, OD, STAGE, PRIORITY, MATCH, \
-                                ACTIONS, STAGE_HINT) \
-    lflow_table_add_lflow(LFLOW_TABLE, OD, NULL, 0, STAGE, PRIORITY, MATCH, \
-                          ACTIONS, NULL, NULL, STAGE_HINT,  \
-                          OVS_SOURCE_LOCATOR, NULL)
-
-#define ovn_lflow_add_with_lflow_ref_hint(LFLOW_TABLE, OD, STAGE, PRIORITY, \
-                                          MATCH, ACTIONS, STAGE_HINT, \
-                                          LFLOW_REF) \
+                                ACTIONS, STAGE_HINT, LFLOW_REF) \
     lflow_table_add_lflow(LFLOW_TABLE, OD, NULL, 0, STAGE, PRIORITY, MATCH, \
                           ACTIONS, NULL, NULL, STAGE_HINT,  \
                           OVS_SOURCE_LOCATOR, LFLOW_REF)
 
 #define ovn_lflow_add_with_dp_group(LFLOW_TABLE, DP_BITMAP, DP_BITMAP_LEN, \
                                     STAGE, PRIORITY, MATCH, ACTIONS, \
-                                    STAGE_HINT) \
+                                    STAGE_HINT, LFLOW_REF) \
     lflow_table_add_lflow(LFLOW_TABLE, NULL, DP_BITMAP, DP_BITMAP_LEN, STAGE, \
                           PRIORITY, MATCH, ACTIONS, NULL, NULL, STAGE_HINT, \
-                          OVS_SOURCE_LOCATOR, NULL)
+                          OVS_SOURCE_LOCATOR, LFLOW_REF)
 
-#define ovn_lflow_add_default_drop(LFLOW_TABLE, OD, STAGE)                    \
+#define ovn_lflow_add_default_drop(LFLOW_TABLE, OD, STAGE, LFLOW_REF)   \
     lflow_table_add_lflow_default_drop(LFLOW_TABLE, OD, STAGE, \
-                                       OVS_SOURCE_LOCATOR, NULL)
+                                       OVS_SOURCE_LOCATOR, LFLOW_REF)
 
 
 /* This macro is similar to ovn_lflow_add_with_hint, except that it requires
@@ -143,20 +129,16 @@  void lflow_table_add_lflow_default_drop(struct lflow_table *,
                           ACTIONS, IN_OUT_PORT, NULL, STAGE_HINT, \
                           OVS_SOURCE_LOCATOR, LFLOW_REF)
 
-#define ovn_lflow_add(LFLOW_TABLE, OD, STAGE, PRIORITY, MATCH, ACTIONS) \
-    lflow_table_add_lflow(LFLOW_TABLE, OD, NULL, 0, STAGE, PRIORITY, MATCH, \
-                          ACTIONS, NULL, NULL, NULL, OVS_SOURCE_LOCATOR, NULL)
-
-#define ovn_lflow_add_with_lflow_ref(LFLOW_TABLE, OD, STAGE, PRIORITY, MATCH, \
-                                     ACTIONS, LFLOW_REF) \
+#define ovn_lflow_add(LFLOW_TABLE, OD, STAGE, PRIORITY, MATCH, ACTIONS, \
+                      LFLOW_REF) \
     lflow_table_add_lflow(LFLOW_TABLE, OD, NULL, 0, STAGE, PRIORITY, MATCH, \
                           ACTIONS, NULL, NULL, NULL, OVS_SOURCE_LOCATOR, \
                           LFLOW_REF)
 
 #define ovn_lflow_metered(LFLOW_TABLE, OD, STAGE, PRIORITY, MATCH, ACTIONS, \
-                          CTRL_METER) \
+                          CTRL_METER, LFLOW_REF) \
     ovn_lflow_add_with_hint__(LFLOW_TABLE, OD, STAGE, PRIORITY, MATCH, \
-                              ACTIONS, NULL, CTRL_METER, NULL)
+                              ACTIONS, NULL, CTRL_METER, NULL, LFLOW_REF)
 
 struct sbrec_logical_dp_group;
 
diff --git a/northd/northd.c b/northd/northd.c
index 13d0db57e2..7c5fe60e9a 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -6063,13 +6063,16 @@  build_lswitch_learn_fdb_op(
 
 static void
 build_lswitch_learn_fdb_od(
-        struct ovn_datapath *od, struct lflow_table *lflows)
+        struct ovn_datapath *od, struct lflow_table *lflows,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbs);
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_LOOKUP_FDB, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_PUT_FDB, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_LOOKUP_FDB, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_PUT_FDB, 0, "1", "next;",
+                  lflow_ref);
     ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 0, "1",
-                  "outport = get_fdb(eth.dst); next;");
+                  "outport = get_fdb(eth.dst); next;", lflow_ref);
 }
 
 /* Egress tables 8: Egress port security - IP (priority 0)
@@ -6077,25 +6080,30 @@  build_lswitch_learn_fdb_od(
  *                 (priority 100). */
 static void
 build_lswitch_output_port_sec_od(struct ovn_datapath *od,
-                              struct lflow_table *lflows)
+                              struct lflow_table *lflows,
+                              struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbs);
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_CHECK_PORT_SEC, 100,
-                  "eth.mcast", REGBIT_PORT_SEC_DROP" = 0; next;");
+                  "eth.mcast", REGBIT_PORT_SEC_DROP" = 0; next;",
+                  lflow_ref);
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_CHECK_PORT_SEC, 0, "1",
-                  REGBIT_PORT_SEC_DROP" = check_out_port_sec(); next;");
+                  REGBIT_PORT_SEC_DROP" = check_out_port_sec(); next;",
+                  lflow_ref);
 
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_APPLY_PORT_SEC, 50,
-                  REGBIT_PORT_SEC_DROP" == 1", debug_drop_action());
+                  REGBIT_PORT_SEC_DROP" == 1", debug_drop_action(),
+                  lflow_ref);
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_APPLY_PORT_SEC, 0,
-                  "1", "output;");
+                  "1", "output;", lflow_ref);
 }
 
 static void
 skip_port_from_conntrack(const struct ovn_datapath *od, struct ovn_port *op,
                          bool has_stateful_acl, enum ovn_stage in_stage,
                          enum ovn_stage out_stage, uint16_t priority,
-                         struct lflow_table *lflows)
+                         struct lflow_table *lflows,
+                         struct lflow_ref *lflow_ref)
 {
     /* Can't use ct() for router ports. Consider the following configuration:
      * lp1(10.0.0.2) on hostA--ls1--lr0--ls2--lp2(10.0.1.2) on hostB, For a
@@ -6117,10 +6125,10 @@  skip_port_from_conntrack(const struct ovn_datapath *od, struct ovn_port *op,
 
     ovn_lflow_add_with_lport_and_hint(lflows, od, in_stage, priority,
                                       ingress_match, ingress_action,
-                                      op->key, &op->nbsp->header_, NULL);
+                                      op->key, &op->nbsp->header_, lflow_ref);
     ovn_lflow_add_with_lport_and_hint(lflows, od, out_stage, priority,
                                       egress_match, egress_action,
-                                      op->key, &op->nbsp->header_, NULL);
+                                      op->key, &op->nbsp->header_, lflow_ref);
 
     free(ingress_match);
     free(egress_match);
@@ -6129,7 +6137,8 @@  skip_port_from_conntrack(const struct ovn_datapath *od, struct ovn_port *op,
 static void
 build_stateless_filter(const struct ovn_datapath *od,
                        const struct nbrec_acl *acl,
-                       struct lflow_table *lflows)
+                       struct lflow_table *lflows,
+                       struct lflow_ref *lflow_ref)
 {
     const char *action = REGBIT_ACL_STATELESS" = 1; next;";
     if (!strcmp(acl->direction, "from-lport")) {
@@ -6137,25 +6146,28 @@  build_stateless_filter(const struct ovn_datapath *od,
                                 acl->priority + OVN_ACL_PRI_OFFSET,
                                 acl->match,
                                 action,
-                                &acl->header_);
+                                &acl->header_,
+                                lflow_ref);
     } else {
         ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL,
                                 acl->priority + OVN_ACL_PRI_OFFSET,
                                 acl->match,
                                 action,
-                                &acl->header_);
+                                &acl->header_,
+                                lflow_ref);
     }
 }
 
 static void
 build_stateless_filters(const struct ovn_datapath *od,
                         const struct ls_port_group_table *ls_port_groups,
-                        struct lflow_table *lflows)
+                        struct lflow_table *lflows,
+                        struct lflow_ref *lflow_ref)
 {
     for (size_t i = 0; i < od->nbs->n_acls; i++) {
         const struct nbrec_acl *acl = od->nbs->acls[i];
         if (!strcmp(acl->action, "allow-stateless")) {
-            build_stateless_filter(od, acl, lflows);
+            build_stateless_filter(od, acl, lflows, lflow_ref);
         }
     }
 
@@ -6171,31 +6183,37 @@  build_stateless_filters(const struct ovn_datapath *od,
             const struct nbrec_acl *acl = ls_pg_rec->nb_pg->acls[i];
 
             if (!strcmp(acl->action, "allow-stateless")) {
-                build_stateless_filter(od, acl, lflows);
+                build_stateless_filter(od, acl, lflows, lflow_ref);
             }
         }
     }
 }
 
 static void
-build_pre_acls(struct ovn_datapath *od, struct lflow_table *lflows)
+build_pre_acls(struct ovn_datapath *od, struct lflow_table *lflows,
+               struct lflow_ref *lflow_ref)
 {
     /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are
      * allowed by default. */
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 0, "1", "next;",
+                  lflow_ref);
 
     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
-                  "eth.dst == $svc_monitor_mac", "next;");
+                  "eth.dst == $svc_monitor_mac", "next;",
+                  lflow_ref);
 
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
-                  "eth.src == $svc_monitor_mac", "next;");
+                  "eth.src == $svc_monitor_mac", "next;",
+                  lflow_ref);
 }
 
 static void
 build_ls_stateful_rec_pre_acls(const struct ls_stateful_record *ls_sful_rec,
                              const struct ls_port_group_table *ls_port_groups,
-                             struct lflow_table *lflows)
+                             struct lflow_table *lflows,
+                             struct lflow_ref *lflow_ref)
 {
     const struct ovn_datapath *od = ls_sful_rec->od;
 
@@ -6206,17 +6224,17 @@  build_ls_stateful_rec_pre_acls(const struct ls_stateful_record *ls_sful_rec,
         for (size_t i = 0; i < od->n_router_ports; i++) {
             skip_port_from_conntrack(od, od->router_ports[i], true,
                                      S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL,
-                                     110, lflows);
+                                     110, lflows, lflow_ref);
         }
         for (size_t i = 0; i < od->n_localnet_ports; i++) {
             skip_port_from_conntrack(od, od->localnet_ports[i], true,
                                      S_SWITCH_IN_PRE_ACL,
                                      S_SWITCH_OUT_PRE_ACL,
-                                     110, lflows);
+                                     110, lflows, lflow_ref);
         }
 
         /* stateless filters always take precedence over stateful ACLs. */
-        build_stateless_filters(od, ls_port_groups, lflows);
+        build_stateless_filters(od, ls_port_groups, lflows, lflow_ref);
 
         /* Ingress and Egress Pre-ACL Table (Priority 110).
          *
@@ -6224,16 +6242,18 @@  build_ls_stateful_rec_pre_acls(const struct ls_stateful_record *ls_sful_rec,
          * unreachable packets. */
         ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
                       "nd || nd_rs || nd_ra || mldv1 || mldv2 || "
-                      "(udp && udp.src == 546 && udp.dst == 547)", "next;");
+                      "(udp && udp.src == 546 && udp.dst == 547)", "next;",
+                      lflow_ref);
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
                       "nd || nd_rs || nd_ra || mldv1 || mldv2 || "
-                      "(udp && udp.src == 546 && udp.dst == 547)", "next;");
+                      "(udp && udp.src == 546 && udp.dst == 547)", "next;",
+                      lflow_ref);
 
         /* Do not send multicast packets to conntrack. */
         ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, "eth.mcast",
-                      "next;");
+                      "next;", lflow_ref);
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, "eth.mcast",
-                      "next;");
+                      "next;", lflow_ref);
 
         /* Ingress and Egress Pre-ACL Table (Priority 100).
          *
@@ -6244,13 +6264,15 @@  build_ls_stateful_rec_pre_acls(const struct ls_stateful_record *ls_sful_rec,
          * 'REGBIT_CONNTRACK_DEFRAG' is set to let the pre-stateful table send
          * it to conntrack for tracking and defragmentation. */
         ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 100, "ip",
-                      REGBIT_CONNTRACK_DEFRAG" = 1; next;");
+                      REGBIT_CONNTRACK_DEFRAG" = 1; next;",
+                      lflow_ref);
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 100, "ip",
-                      REGBIT_CONNTRACK_DEFRAG" = 1; next;");
+                      REGBIT_CONNTRACK_DEFRAG" = 1; next;",
+                      lflow_ref);
     } else if (ls_sful_rec->has_lb_vip) {
         /* We'll build stateless filters if there are LB rules so that
          * the stateless flows are not tracked in pre-lb. */
-         build_stateless_filters(od, ls_port_groups, lflows);
+         build_stateless_filters(od, ls_port_groups, lflows, lflow_ref);
     }
 }
 
@@ -6314,7 +6336,8 @@  build_empty_lb_event_flow(struct ovn_lb_vip *lb_vip,
 static void
 build_interconn_mcast_snoop_flows(struct ovn_datapath *od,
                                   const struct shash *meter_groups,
-                                  struct lflow_table *lflows)
+                                  struct lflow_table *lflows,
+                                   struct lflow_ref *lflow_ref)
 {
     struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw;
     if (!mcast_sw_info->enabled
@@ -6333,7 +6356,8 @@  build_interconn_mcast_snoop_flows(struct ovn_datapath *od,
         ovn_lflow_metered(lflows, od, S_SWITCH_OUT_PRE_LB, 120, match,
                           "clone { igmp; }; next;",
                           copp_meter_get(COPP_IGMP, od->nbs->copp,
-                                         meter_groups));
+                                         meter_groups),
+                          lflow_ref);
         free(match);
 
         /* Punt MLD traffic to controller. */
@@ -6341,50 +6365,54 @@  build_interconn_mcast_snoop_flows(struct ovn_datapath *od,
         ovn_lflow_metered(lflows, od, S_SWITCH_OUT_PRE_LB, 120, match,
                           "clone { igmp; }; next;",
                           copp_meter_get(COPP_IGMP, od->nbs->copp,
-                                         meter_groups));
+                                         meter_groups),
+                          lflow_ref);
         free(match);
     }
 }
 
 static void
 build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups,
-             struct lflow_table *lflows)
+             struct lflow_table *lflows, struct lflow_ref *lflow_ref)
 {
     /* Handle IGMP/MLD packets crossing AZs. */
-    build_interconn_mcast_snoop_flows(od, meter_groups, lflows);
+    build_interconn_mcast_snoop_flows(od, meter_groups, lflows, lflow_ref);
 
     /* Do not send multicast packets to conntrack */
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, "eth.mcast", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, "eth.mcast", "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, "eth.mcast", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, "eth.mcast", "next;",
+                  lflow_ref);
 
     /* Do not send ND packets to conntrack */
     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110,
                   "nd || nd_rs || nd_ra || mldv1 || mldv2",
-                  "next;");
+                  "next;", lflow_ref);
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110,
                   "nd || nd_rs || nd_ra || mldv1 || mldv2",
-                  "next;");
+                  "next;", lflow_ref);
 
     /* Do not send service monitor packets to conntrack. */
     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110,
-                  "eth.dst == $svc_monitor_mac", "next;");
+                  "eth.dst == $svc_monitor_mac", "next;", lflow_ref);
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110,
-                  "eth.src == $svc_monitor_mac", "next;");
+                  "eth.src == $svc_monitor_mac", "next;", lflow_ref);
 
     /* Allow all packets to go to next tables by default. */
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 0, "1", "next;", lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 0, "1", "next;", lflow_ref);
 
     /* Do not send statless flows via conntrack */
     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110,
-                  REGBIT_ACL_STATELESS" == 1", "next;");
+                  REGBIT_ACL_STATELESS" == 1", "next;", lflow_ref);
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110,
-                  REGBIT_ACL_STATELESS" == 1", "next;");
+                  REGBIT_ACL_STATELESS" == 1", "next;", lflow_ref);
 }
 
 static void
 build_ls_stateful_rec_pre_lb(const struct ls_stateful_record *ls_stateful_rec,
-                             struct lflow_table *lflows)
+                             struct lflow_table *lflows,
+                             struct lflow_ref *lflow_ref)
 {
     const struct ovn_datapath *od = ls_stateful_rec->od;
 
@@ -6392,7 +6420,7 @@  build_ls_stateful_rec_pre_lb(const struct ls_stateful_record *ls_stateful_rec,
         skip_port_from_conntrack(od, od->router_ports[i],
                                  ls_stateful_rec->has_stateful_acl,
                                  S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB,
-                                 110, lflows);
+                                 110, lflows, lflow_ref);
     }
 
     /* Localnet ports have no need for going through conntrack, unless
@@ -6405,7 +6433,7 @@  build_ls_stateful_rec_pre_lb(const struct ls_stateful_record *ls_stateful_rec,
             skip_port_from_conntrack(od, od->localnet_ports[i],
                                      ls_stateful_rec->has_stateful_acl,
                                      S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB,
-                                     110, lflows);
+                                     110, lflows, lflow_ref);
         }
     }
 
@@ -6441,21 +6469,26 @@  build_ls_stateful_rec_pre_lb(const struct ls_stateful_record *ls_stateful_rec,
      */
     if (ls_stateful_rec->has_lb_vip) {
         ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB,
-                      100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;");
+                      100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;",
+                      lflow_ref);
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB,
-                      100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;");
+                      100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;",
+                      lflow_ref);
     }
 }
 
 static void
 build_pre_stateful(struct ovn_datapath *od,
                    const struct chassis_features *features,
-                   struct lflow_table *lflows)
+                   struct lflow_table *lflows,
+                   struct lflow_ref *lflow_ref)
 {
     /* Ingress and Egress pre-stateful Table (Priority 0): Packets are
      * allowed by default. */
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 0, "1", "next;",
+                  lflow_ref);
 
     /* Note: priority-120 flows are added in build_lb_rules_pre_stateful(). */
 
@@ -6464,25 +6497,30 @@  build_pre_stateful(struct ovn_datapath *od,
                                : "ct_lb;";
 
     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 110,
-                  REGBIT_CONNTRACK_NAT" == 1", ct_lb_action);
+                  REGBIT_CONNTRACK_NAT" == 1", ct_lb_action,
+                  lflow_ref);
 
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 110,
-                  REGBIT_CONNTRACK_NAT" == 1", ct_lb_action);
+                  REGBIT_CONNTRACK_NAT" == 1", ct_lb_action,
+                  lflow_ref);
 
     /* If REGBIT_CONNTRACK_DEFRAG is set as 1, then the packets should be
      * sent to conntrack for tracking and defragmentation. */
     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 100,
-                  REGBIT_CONNTRACK_DEFRAG" == 1", "ct_next;");
+                  REGBIT_CONNTRACK_DEFRAG" == 1", "ct_next;",
+                  lflow_ref);
 
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 100,
-                  REGBIT_CONNTRACK_DEFRAG" == 1", "ct_next;");
+                  REGBIT_CONNTRACK_DEFRAG" == 1", "ct_next;",
+                  lflow_ref);
 
 }
 
 static void
 build_acl_hints(const struct ls_stateful_record *ls_sful_rec,
                 const struct chassis_features *features,
-                struct lflow_table *lflows)
+                struct lflow_table *lflows,
+                struct lflow_ref *lflow_ref)
 {
     const struct ovn_datapath *od = ls_sful_rec->od;
 
@@ -6510,9 +6548,10 @@  build_acl_hints(const struct ls_stateful_record *ls_sful_rec,
 
         /* In any case, advance to the next stage. */
         if (!ls_sful_rec->has_acls && !ls_sful_rec->has_lb_vip) {
-            ovn_lflow_add(lflows, od, stage, UINT16_MAX, "1", "next;");
+            ovn_lflow_add(lflows, od, stage, UINT16_MAX, "1", "next;",
+                          lflow_ref);
         } else {
-            ovn_lflow_add(lflows, od, stage, 0, "1", "next;");
+            ovn_lflow_add(lflows, od, stage, 0, "1", "next;", lflow_ref);
         }
 
         if (!ls_sful_rec->has_stateful_acl && !ls_sful_rec->has_lb_vip) {
@@ -6526,7 +6565,7 @@  build_acl_hints(const struct ls_stateful_record *ls_sful_rec,
         ovn_lflow_add(lflows, od, stage, 7, "ct.new && !ct.est",
                       REGBIT_ACL_HINT_ALLOW_NEW " = 1; "
                       REGBIT_ACL_HINT_DROP " = 1; "
-                      "next;");
+                      "next;", lflow_ref);
 
         /* Already established connections in the "request" direction that
          * are already marked as "blocked" may hit either:
@@ -6542,13 +6581,13 @@  build_acl_hints(const struct ls_stateful_record *ls_sful_rec,
         ovn_lflow_add(lflows, od, stage, 6, match,
                       REGBIT_ACL_HINT_ALLOW_NEW " = 1; "
                       REGBIT_ACL_HINT_DROP " = 1; "
-                      "next;");
+                      "next;", lflow_ref);
 
         /* Not tracked traffic can either be allowed or dropped. */
         ovn_lflow_add(lflows, od, stage, 5, "!ct.trk",
                       REGBIT_ACL_HINT_ALLOW " = 1; "
                       REGBIT_ACL_HINT_DROP " = 1; "
-                      "next;");
+                      "next;", lflow_ref);
 
         /* Already established connections in the "request" direction may hit
          * either:
@@ -6564,20 +6603,20 @@  build_acl_hints(const struct ls_stateful_record *ls_sful_rec,
         ovn_lflow_add(lflows, od, stage, 4, match,
                       REGBIT_ACL_HINT_ALLOW " = 1; "
                       REGBIT_ACL_HINT_BLOCK " = 1; "
-                      "next;");
+                      "next;", lflow_ref);
 
         /* Not established or established and already blocked connections may
          * hit drop ACLs.
          */
         ovn_lflow_add(lflows, od, stage, 3, "!ct.est",
                       REGBIT_ACL_HINT_DROP " = 1; "
-                      "next;");
+                      "next;", lflow_ref);
         match = features->ct_no_masked_label
                 ? "ct.est && ct_mark.blocked == 1"
                 : "ct.est && ct_label.blocked == 1";
         ovn_lflow_add(lflows, od, stage, 2, match,
                       REGBIT_ACL_HINT_DROP " = 1; "
-                      "next;");
+                      "next;", lflow_ref);
 
         /* Established connections that were previously allowed might hit
          * drop ACLs in which case the connection must be committed with
@@ -6588,7 +6627,7 @@  build_acl_hints(const struct ls_stateful_record *ls_sful_rec,
                 : "ct.est && ct_label.blocked == 0";
         ovn_lflow_add(lflows, od, stage, 1, match,
                       REGBIT_ACL_HINT_BLOCK " = 1; "
-                      "next;");
+                      "next;", lflow_ref);
     }
 }
 
@@ -6654,7 +6693,8 @@  static void
 consider_acl(struct lflow_table *lflows, const struct ovn_datapath *od,
              const struct nbrec_acl *acl, bool has_stateful,
              bool ct_masked_mark, const struct shash *meter_groups,
-             uint64_t max_acl_tier, struct ds *match, struct ds *actions)
+             uint64_t max_acl_tier, struct ds *match, struct ds *actions,
+             struct lflow_ref *lflow_ref)
 {
     const char *ct_blocked_match = ct_masked_mark
                                    ? "ct_mark.blocked"
@@ -6703,7 +6743,7 @@  consider_acl(struct lflow_table *lflows, const struct ovn_datapath *od,
         ds_put_format(match, "(%s)", acl->match);
         ovn_lflow_add_with_hint(lflows, od, stage, priority,
                                 ds_cstr(match), ds_cstr(actions),
-                                &acl->header_);
+                                &acl->header_, lflow_ref);
         return;
     }
 
@@ -6740,7 +6780,7 @@  consider_acl(struct lflow_table *lflows, const struct ovn_datapath *od,
         ds_put_cstr(actions, "next;");
         ovn_lflow_add_with_hint(lflows, od, stage, priority,
                                 ds_cstr(match), ds_cstr(actions),
-                                &acl->header_);
+                                &acl->header_, lflow_ref);
 
         /* Match on traffic in the request direction for an established
          * connection tracking entry that has not been marked for
@@ -6762,7 +6802,7 @@  consider_acl(struct lflow_table *lflows, const struct ovn_datapath *od,
         ds_put_cstr(actions, "next;");
         ovn_lflow_add_with_hint(lflows, od, stage, priority,
                                 ds_cstr(match), ds_cstr(actions),
-                                &acl->header_);
+                                &acl->header_, lflow_ref);
     } else if (!strcmp(acl->action, "drop")
                || !strcmp(acl->action, "reject")) {
         /* The implementation of "drop" differs if stateful ACLs are in
@@ -6779,7 +6819,7 @@  consider_acl(struct lflow_table *lflows, const struct ovn_datapath *od,
         ds_put_cstr(actions, "next;");
         ovn_lflow_add_with_hint(lflows, od, stage, priority,
                                 ds_cstr(match), ds_cstr(actions),
-                                &acl->header_);
+                                &acl->header_, lflow_ref);
         /* For an existing connection without ct_mark.blocked set, we've
          * encountered a policy change. ACLs previously allowed
          * this connection and we committed the connection tracking
@@ -6800,7 +6840,7 @@  consider_acl(struct lflow_table *lflows, const struct ovn_datapath *od,
                       ct_blocked_match);
         ovn_lflow_add_with_hint(lflows, od, stage, priority,
                                 ds_cstr(match), ds_cstr(actions),
-                                &acl->header_);
+                                &acl->header_, lflow_ref);
     }
 }
 
@@ -6883,7 +6923,8 @@  build_acl_action_lflows(const struct ls_stateful_record *ls_stateful_rec,
                         const char *default_acl_action,
                         const struct shash *meter_groups,
                         struct ds *match,
-                        struct ds *actions)
+                        struct ds *actions,
+                        struct lflow_ref *lflow_ref)
 {
     const struct ovn_datapath *od = ls_stateful_rec->od;
 
@@ -6906,18 +6947,20 @@  build_acl_action_lflows(const struct ls_stateful_record *ls_stateful_rec,
     for (size_t i = 0; i < ARRAY_SIZE(stages); i++) {
         enum ovn_stage stage = stages[i];
         if (!ls_stateful_rec->has_acls) {
-            ovn_lflow_add(lflows, od, stage, 0, "1", "next;");
+            ovn_lflow_add(lflows, od, stage, 0, "1", "next;", lflow_ref);
             continue;
         }
         ds_truncate(actions, verdict_len);
         ds_put_cstr(actions, "next;");
         ovn_lflow_add(lflows, od, stage, 1000,
-                      REGBIT_ACL_VERDICT_ALLOW " == 1", ds_cstr(actions));
+                      REGBIT_ACL_VERDICT_ALLOW " == 1", ds_cstr(actions),
+                      lflow_ref);
         ds_truncate(actions, verdict_len);
         ds_put_cstr(actions, debug_implicit_drop_action());
         ovn_lflow_add(lflows, od, stage, 1000,
                       REGBIT_ACL_VERDICT_DROP " == 1",
-                      ds_cstr(actions));
+                      ds_cstr(actions),
+                      lflow_ref);
         bool ingress = ovn_stage_get_pipeline(stage) == P_IN;
 
         ds_truncate(actions, verdict_len);
@@ -6933,11 +6976,11 @@  build_acl_action_lflows(const struct ls_stateful_record *ls_stateful_rec,
         ovn_lflow_metered(lflows, od, stage, 1000,
                           REGBIT_ACL_VERDICT_REJECT " == 1", ds_cstr(actions),
                           copp_meter_get(COPP_REJECT, od->nbs->copp,
-                          meter_groups));
+                          meter_groups), lflow_ref);
 
         ds_truncate(actions, verdict_len);
         ds_put_cstr(actions, default_acl_action);
-        ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions));
+        ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions), lflow_ref);
 
         struct ds tier_actions = DS_EMPTY_INITIALIZER;
         for (size_t j = 0; j < ls_stateful_rec->max_acl_tier; j++) {
@@ -6949,7 +6992,7 @@  build_acl_action_lflows(const struct ls_stateful_record *ls_stateful_rec,
                           j + 1, ingress ? "ingress" : "egress",
                           ovn_stage_get_table(stage) - 1);
             ovn_lflow_add(lflows, od, stage, 500, ds_cstr(match),
-                         ds_cstr(&tier_actions));
+                         ds_cstr(&tier_actions), lflow_ref);
         }
         ds_destroy(&tier_actions);
     }
@@ -6961,7 +7004,8 @@  build_acl_log_related_flows(const struct ovn_datapath *od,
                             const struct nbrec_acl *acl, bool has_stateful,
                             bool ct_masked_mark,
                             const struct shash *meter_groups,
-                            struct ds *match, struct ds *actions)
+                            struct ds *match, struct ds *actions,
+                            struct lflow_ref *lflow_ref)
 {
     /* Related and reply traffic are universally allowed by priority
      * 65532 flows created in build_acls(). If logging is enabled on
@@ -7015,7 +7059,7 @@  build_acl_log_related_flows(const struct ovn_datapath *od,
     ovn_lflow_add_with_hint(lflows, od, log_related_stage,
                             UINT16_MAX - 2,
                             ds_cstr(match), ds_cstr(actions),
-                            &acl->header_);
+                            &acl->header_, lflow_ref);
 
     ds_clear(match);
     ds_put_format(match, "!ct.est && ct.rel && !ct.new%s && "
@@ -7026,7 +7070,7 @@  build_acl_log_related_flows(const struct ovn_datapath *od,
     ovn_lflow_add_with_hint(lflows, od, log_related_stage,
                             UINT16_MAX - 2,
                             ds_cstr(match), ds_cstr(actions),
-                            &acl->header_);
+                            &acl->header_, lflow_ref);
 }
 
 static void
@@ -7034,7 +7078,8 @@  build_acls(const struct ls_stateful_record *ls_stateful_rec,
            const struct chassis_features *features,
            struct lflow_table *lflows,
            const struct ls_port_group_table *ls_port_groups,
-           const struct shash *meter_groups)
+           const struct shash *meter_groups,
+           struct lflow_ref *lflow_ref)
 {
     const struct ovn_datapath *od = ls_stateful_rec->od;
 
@@ -7059,20 +7104,24 @@  build_acls(const struct ls_stateful_record *ls_stateful_rec,
     if (!ls_stateful_rec->has_acls) {
         if (!ls_stateful_rec->has_lb_vip) {
             ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX, "1",
-                          "next;");
+                          "next;", lflow_ref);
             ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX, "1",
-                          "next;");
+                          "next;", lflow_ref);
         } else {
-            ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 0, "1", "next;");
-            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 0, "1", "next;");
+            ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 0, "1", "next;",
+                          lflow_ref);
+            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 0, "1", "next;",
+                          lflow_ref);
         }
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL, 0, "1",
-                      "next;");
+                      "next;", lflow_ref);
     } else {
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 0, "1", "next;");
-        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 0, "1", "next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 0, "1", "next;",
+                      lflow_ref);
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 0, "1", "next;",
+                      lflow_ref);
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL, 0, "1",
-                      "next;");
+                      "next;", lflow_ref);
     }
 
 
@@ -7104,19 +7153,21 @@  build_acls(const struct ls_stateful_record *ls_stateful_rec,
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 1,
                       ds_cstr(&match),
                       REGBIT_CONNTRACK_COMMIT" = 1; "
-                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
+                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;",
+                      lflow_ref);
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 1,
                       ds_cstr(&match),
                       REGBIT_CONNTRACK_COMMIT" = 1; "
-                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
+                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;",
+                      lflow_ref);
 
         const char *next_action = default_acl_drop
                              ? "next;"
                              : REGBIT_CONNTRACK_COMMIT" = 1; next;";
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 1, "ip && !ct.est",
-                      next_action);
+                      next_action, lflow_ref);
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 1, "ip && !ct.est",
-                      next_action);
+                      next_action, lflow_ref);
 
         /* Ingress and Egress ACL Table (Priority 65532).
          *
@@ -7130,9 +7181,11 @@  build_acls(const struct ls_stateful_record *ls_stateful_rec,
                       use_ct_inv_match ? "ct.inv || " : "",
                       ct_blocked_match);
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
-                      ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1; next;");
+                      ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1; next;",
+                      lflow_ref);
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
-                      ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1; next;");
+                      ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1; next;",
+                      lflow_ref);
 
         /* Ingress and Egress ACL Table (Priority 65535 - 3).
          *
@@ -7152,10 +7205,12 @@  build_acls(const struct ls_stateful_record *ls_stateful_rec,
                       ds_cstr(&match), REGBIT_ACL_HINT_DROP" = 0; "
                       REGBIT_ACL_HINT_BLOCK" = 0; "
                       REGBIT_ACL_HINT_ALLOW_REL" = 1; "
-                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
+                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;",
+                      lflow_ref);
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
                       ds_cstr(&match),
-                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
+                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
+                      lflow_ref);
 
         /* Ingress and Egress ACL Table (Priority 65535).
          *
@@ -7184,15 +7239,16 @@  build_acls(const struct ls_stateful_record *ls_stateful_rec,
                       use_ct_inv_match ? " && !ct.inv" : "",
                       ct_blocked_match);
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
-                      ds_cstr(&match), ct_in_acl_action);
+                      ds_cstr(&match), ct_in_acl_action, lflow_ref);
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
-                      ds_cstr(&match), ct_out_acl_action);
+                      ds_cstr(&match), ct_out_acl_action, lflow_ref);
         /* Reply and related traffic matched by an "allow-related" ACL
          * should be allowed in the ls_in_acl_after_lb stage too. */
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL,
                       UINT16_MAX - 3,
                       REGBIT_ACL_HINT_ALLOW_REL" == 1",
-                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
+                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
+                      lflow_ref);
     }
 
     /* Ingress and Egress ACL Table (Priority 65532).
@@ -7204,24 +7260,28 @@  build_acls(const struct ls_stateful_record *ls_stateful_rec,
      * https://bugzilla.kernel.org/show_bug.cgi?id=11797. */
     ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
                   IPV6_CT_OMIT_MATCH,
-                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
+                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
+                  lflow_ref);
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
                   IPV6_CT_OMIT_MATCH,
-                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
+                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
+                  lflow_ref);
     ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL, UINT16_MAX - 3,
                   IPV6_CT_OMIT_MATCH,
-                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
+                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
+                  lflow_ref);
 
     /* Ingress or Egress ACL Table (Various priorities). */
     for (size_t i = 0; i < od->nbs->n_acls; i++) {
         struct nbrec_acl *acl = od->nbs->acls[i];
         build_acl_log_related_flows(od, lflows, acl, has_stateful,
                                     features->ct_no_masked_label,
-                                    meter_groups, &match, &actions);
+                                    meter_groups, &match, &actions,
+                                    lflow_ref);
         consider_acl(lflows, od, acl, has_stateful,
                      features->ct_no_masked_label,
                      meter_groups, ls_stateful_rec->max_acl_tier,
-                     &match, &actions);
+                     &match, &actions, lflow_ref);
     }
 
     const struct ls_port_group *ls_pg =
@@ -7234,11 +7294,12 @@  build_acls(const struct ls_stateful_record *ls_stateful_rec,
 
                 build_acl_log_related_flows(od, lflows, acl, has_stateful,
                                             features->ct_no_masked_label,
-                                            meter_groups, &match, &actions);
+                                            meter_groups, &match, &actions,
+                                            lflow_ref);
                 consider_acl(lflows, od, acl, has_stateful,
                              features->ct_no_masked_label,
                              meter_groups, ls_stateful_rec->max_acl_tier,
-                             &match, &actions);
+                             &match, &actions, lflow_ref);
             }
         }
     }
@@ -7253,7 +7314,7 @@  build_acls(const struct ls_stateful_record *ls_stateful_rec,
                          : REGBIT_ACL_VERDICT_ALLOW" = 1; next;";
         ovn_lflow_add(
             lflows, od, S_SWITCH_OUT_ACL_EVAL, 34000, "udp.src == 53",
-            dns_actions);
+            dns_actions, lflow_ref);
     }
 
     if (ls_stateful_rec->has_acls || ls_stateful_rec->has_lb_vip) {
@@ -7261,30 +7322,37 @@  build_acls(const struct ls_stateful_record *ls_stateful_rec,
         * packets to skip applying ingress ACLs. */
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 34000,
                     "eth.dst == $svc_monitor_mac",
-                    REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
+                    REGBIT_ACL_VERDICT_ALLOW" = 1; next;",
+                    lflow_ref);
 
         /* Add a 34000 priority flow to advance the service monitor packets
         * generated by ovn-controller to skip applying egress ACLs. */
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 34000,
                     "eth.src == $svc_monitor_mac",
-                    REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
+                    REGBIT_ACL_VERDICT_ALLOW" = 1; next;",
+                    lflow_ref);
     }
 
     build_acl_action_lflows(ls_stateful_rec, lflows, default_acl_action,
-                            meter_groups, &match, &actions);
+                            meter_groups, &match, &actions, lflow_ref);
 
     ds_destroy(&match);
     ds_destroy(&actions);
 }
 
 static void
-build_qos(struct ovn_datapath *od, struct lflow_table *lflows) {
+build_qos(struct ovn_datapath *od, struct lflow_table *lflows,
+          struct lflow_ref *lflow_ref) {
     struct ds action = DS_EMPTY_INITIALIZER;
 
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_QOS_MARK, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_OUT_QOS_MARK, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_QOS_METER, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_OUT_QOS_METER, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_QOS_MARK, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_OUT_QOS_MARK, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_QOS_METER, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_OUT_QOS_METER, 0, "1", "next;",
+                  lflow_ref);
 
     for (size_t i = 0; i < od->nbs->n_qos_rules; i++) {
         struct nbrec_qos *qos = od->nbs->qos_rules[i];
@@ -7301,7 +7369,7 @@  build_qos(struct ovn_datapath *od, struct lflow_table *lflows) {
                 ovn_lflow_add_with_hint(lflows, od, stage,
                                         qos->priority,
                                         qos->match, ds_cstr(&action),
-                                        &qos->header_);
+                                        &qos->header_, lflow_ref);
             }
         }
 
@@ -7332,7 +7400,7 @@  build_qos(struct ovn_datapath *od, struct lflow_table *lflows) {
             ovn_lflow_add_with_hint(lflows, od, stage,
                                     qos->priority,
                                     qos->match, ds_cstr(&action),
-                                    &qos->header_);
+                                    &qos->header_, lflow_ref);
         }
     }
     ds_destroy(&action);
@@ -7343,7 +7411,8 @@  build_lb_rules_pre_stateful(struct lflow_table *lflows,
                             struct ovn_lb_datapaths *lb_dps,
                             bool ct_lb_mark,
                             const struct ovn_datapaths *ls_datapaths,
-                            struct ds *match, struct ds *action)
+                            struct ds *match, struct ds *action,
+                            struct lflow_ref *lflow_ref)
 {
     if (!lb_dps->n_nb_ls) {
         return;
@@ -7397,7 +7466,7 @@  build_lb_rules_pre_stateful(struct lflow_table *lflows,
         ovn_lflow_add_with_dp_group(
             lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths),
             S_SWITCH_IN_PRE_STATEFUL, 120, ds_cstr(match), ds_cstr(action),
-            &lb->nlb->header_);
+            &lb->nlb->header_, lflow_ref);
     }
 }
 
@@ -7445,7 +7514,8 @@  build_lb_affinity_lr_flows(struct lflow_table *lflows,
                            const struct ovn_northd_lb *lb,
                            struct ovn_lb_vip *lb_vip, char *new_lb_match,
                            char *lb_action, const unsigned long *dp_bitmap,
-                           const struct ovn_datapaths *lr_datapaths)
+                           const struct ovn_datapaths *lr_datapaths,
+                           struct lflow_ref *lflow_ref)
 {
     if (!lb->affinity_timeout ||
         bitmap_is_all_zeros(dp_bitmap, ods_size(lr_datapaths))) {
@@ -7484,7 +7554,8 @@  build_lb_affinity_lr_flows(struct lflow_table *lflows,
 
     ovn_lflow_add_with_dp_group(
         lflows, dp_bitmap, ods_size(lr_datapaths), S_ROUTER_IN_LB_AFF_CHECK,
-        100, new_lb_match, ds_cstr(&aff_check_action), &lb->nlb->header_);
+        100, new_lb_match, ds_cstr(&aff_check_action), &lb->nlb->header_,
+        lflow_ref);
 
     /* Prepare common part of affinity LB and affinity learn action. */
     ds_put_format(&aff_action, "%s = %s; ", reg_vip, lb_vip->vip_str);
@@ -7566,12 +7637,14 @@  build_lb_affinity_lr_flows(struct lflow_table *lflows,
         ovn_lflow_add_with_dp_group(
             lflows, dp_bitmap, ods_size(lr_datapaths),
             S_ROUTER_IN_LB_AFF_LEARN, 100, ds_cstr(&aff_match_learn),
-            ds_cstr(&aff_action_learn), &lb->nlb->header_);
+            ds_cstr(&aff_action_learn), &lb->nlb->header_,
+            lflow_ref);
 
         /* Use already selected backend within affinity timeslot. */
         ovn_lflow_add_with_dp_group(
             lflows, dp_bitmap, ods_size(lr_datapaths), S_ROUTER_IN_DNAT, 150,
-            ds_cstr(&aff_match), ds_cstr(&aff_action), &lb->nlb->header_);
+            ds_cstr(&aff_match), ds_cstr(&aff_action), &lb->nlb->header_,
+            lflow_ref);
 
         ds_truncate(&aff_action, aff_action_len);
         ds_truncate(&aff_action_learn, aff_action_learn_len);
@@ -7631,7 +7704,8 @@  static void
 build_lb_affinity_ls_flows(struct lflow_table *lflows,
                            struct ovn_lb_datapaths *lb_dps,
                            struct ovn_lb_vip *lb_vip,
-                           const struct ovn_datapaths *ls_datapaths)
+                           const struct ovn_datapaths *ls_datapaths,
+                           struct lflow_ref *lflow_ref)
 {
     if (!lb_dps->lb->affinity_timeout || !lb_dps->n_nb_ls) {
         return;
@@ -7659,7 +7733,7 @@  build_lb_affinity_ls_flows(struct lflow_table *lflows,
     ovn_lflow_add_with_dp_group(
         lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths),
         S_SWITCH_IN_LB_AFF_CHECK, 100, ds_cstr(&new_lb_match), aff_check,
-        &lb_dps->lb->nlb->header_);
+        &lb_dps->lb->nlb->header_, lflow_ref);
     ds_destroy(&new_lb_match);
 
     struct ds aff_action = DS_EMPTY_INITIALIZER;
@@ -7749,13 +7823,14 @@  build_lb_affinity_ls_flows(struct lflow_table *lflows,
         ovn_lflow_add_with_dp_group(
             lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths),
             S_SWITCH_IN_LB_AFF_LEARN, 100, ds_cstr(&aff_match_learn),
-            ds_cstr(&aff_action_learn), &lb->nlb->header_);
+            ds_cstr(&aff_action_learn), &lb->nlb->header_,
+            lflow_ref);
 
         /* Use already selected backend within affinity timeslot. */
         ovn_lflow_add_with_dp_group(
             lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths),
             S_SWITCH_IN_LB, 150, ds_cstr(&aff_match), ds_cstr(&aff_action),
-            &lb->nlb->header_);
+            &lb->nlb->header_, lflow_ref);
 
         ds_truncate(&aff_action, aff_action_len);
         ds_truncate(&aff_action_learn, aff_action_learn_len);
@@ -7771,20 +7846,26 @@  build_lb_affinity_ls_flows(struct lflow_table *lflows,
 
 static void
 build_lswitch_lb_affinity_default_flows(struct ovn_datapath *od,
-                                        struct lflow_table *lflows)
+                                        struct lflow_table *lflows,
+                                        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbs);
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_CHECK, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_LEARN, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_CHECK, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_LEARN, 0, "1", "next;",
+                  lflow_ref);
 }
 
 static void
 build_lrouter_lb_affinity_default_flows(struct ovn_datapath *od,
-                                        struct lflow_table *lflows)
+                                        struct lflow_table *lflows,
+                                        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
-    ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_CHECK, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_LEARN, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_CHECK, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_LEARN, 0, "1", "next;",
+                  lflow_ref);
 }
 
 static void
@@ -7792,7 +7873,8 @@  build_lb_rules(struct lflow_table *lflows, struct ovn_lb_datapaths *lb_dps,
                const struct ovn_datapaths *ls_datapaths,
                const struct chassis_features *features, struct ds *match,
                struct ds *action, const struct shash *meter_groups,
-               const struct hmap *svc_monitor_map)
+               const struct hmap *svc_monitor_map,
+               struct lflow_ref *lflow_ref)
 {
     const struct ovn_northd_lb *lb = lb_dps->lb;
     for (size_t i = 0; i < lb->n_vips; i++) {
@@ -7829,7 +7911,8 @@  build_lb_rules(struct lflow_table *lflows, struct ovn_lb_datapaths *lb_dps,
             priority = 120;
         }
 
-        build_lb_affinity_ls_flows(lflows, lb_dps, lb_vip, ls_datapaths);
+        build_lb_affinity_ls_flows(lflows, lb_dps, lb_vip, ls_datapaths,
+                                   lflow_ref);
 
         unsigned long *dp_non_meter = NULL;
         bool build_non_meter = false;
@@ -7852,14 +7935,16 @@  build_lb_rules(struct lflow_table *lflows, struct ovn_lb_datapaths *lb_dps,
                 ovn_lflow_add_with_hint__(
                         lflows, od, S_SWITCH_IN_LB, priority,
                         ds_cstr(match), ds_cstr(action),
-                        NULL, meter, &lb->nlb->header_);
+                        NULL, meter, &lb->nlb->header_,
+                        lflow_ref);
             }
         }
         if (!reject || build_non_meter) {
             ovn_lflow_add_with_dp_group(
                 lflows, dp_non_meter ? dp_non_meter : lb_dps->nb_ls_map,
                 ods_size(ls_datapaths), S_SWITCH_IN_LB, priority,
-                ds_cstr(match), ds_cstr(action), &lb->nlb->header_);
+                ds_cstr(match), ds_cstr(action), &lb->nlb->header_,
+                lflow_ref);
         }
         bitmap_free(dp_non_meter);
     }
@@ -7868,7 +7953,8 @@  build_lb_rules(struct lflow_table *lflows, struct ovn_lb_datapaths *lb_dps,
 static void
 build_stateful(struct ovn_datapath *od,
                const struct chassis_features *features,
-               struct lflow_table *lflows)
+               struct lflow_table *lflows,
+               struct lflow_ref *lflow_ref)
 {
     const char *ct_block_action = features->ct_no_masked_label
                                   ? "ct_mark.blocked"
@@ -7877,9 +7963,11 @@  build_stateful(struct ovn_datapath *od,
 
     /* Ingress LB, Ingress and Egress stateful Table (Priority 0): Packets are
      * allowed by default. */
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_LB, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_LB, 0, "1", "next;", lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 0, "1", "next;",
+                  lflow_ref);
 
     /* If REGBIT_CONNTRACK_COMMIT is set as 1 and
      * REGBIT_CONNTRACK_SET_LABEL is set to 1, then the packets should be
@@ -7893,11 +7981,13 @@  build_stateful(struct ovn_datapath *od,
     ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100,
                   REGBIT_CONNTRACK_COMMIT" == 1 && "
                   REGBIT_ACL_LABEL" == 1",
-                  ds_cstr(&actions));
+                  ds_cstr(&actions),
+                  lflow_ref);
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 100,
                   REGBIT_CONNTRACK_COMMIT" == 1 && "
                   REGBIT_ACL_LABEL" == 1",
-                  ds_cstr(&actions));
+                  ds_cstr(&actions),
+                  lflow_ref);
 
     /* If REGBIT_CONNTRACK_COMMIT is set as 1, then the packets should be
      * committed to conntrack. We always set ct_mark.blocked to 0 here as
@@ -7908,26 +7998,32 @@  build_stateful(struct ovn_datapath *od,
     ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100,
                   REGBIT_CONNTRACK_COMMIT" == 1 && "
                   REGBIT_ACL_LABEL" == 0",
-                  ds_cstr(&actions));
+                  ds_cstr(&actions),
+                  lflow_ref);
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 100,
                   REGBIT_CONNTRACK_COMMIT" == 1 && "
                   REGBIT_ACL_LABEL" == 0",
-                  ds_cstr(&actions));
+                  ds_cstr(&actions),
+                  lflow_ref);
     ds_destroy(&actions);
 }
 
 static void
 build_lb_hairpin(const struct ls_stateful_record *ls_stateful_rec,
-                 struct lflow_table *lflows)
+                 struct lflow_table *lflows,
+                 struct lflow_ref *lflow_ref)
 {
     const struct ovn_datapath *od = ls_stateful_rec->od;
 
     /* Ingress Pre-Hairpin/Nat-Hairpin/Hairpin tabled (Priority 0).
      * Packets that don't need hairpinning should continue processing.
      */
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_NAT_HAIRPIN, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_NAT_HAIRPIN, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 0, "1", "next;",
+                  lflow_ref);
 
     if (ls_stateful_rec->has_lb_vip) {
         /* Check if the packet needs to be hairpinned.
@@ -7939,7 +8035,8 @@  build_lb_hairpin(const struct ls_stateful_record *ls_stateful_rec,
             REGBIT_HAIRPIN " = chk_lb_hairpin(); "
             REGBIT_HAIRPIN_REPLY " = chk_lb_hairpin_reply(); "
             "next;",
-            &od->nbs->header_);
+            &od->nbs->header_,
+            lflow_ref);
 
         /* If packet needs to be hairpinned, snat the src ip with the VIP
          * for new sessions. */
@@ -7947,7 +8044,8 @@  build_lb_hairpin(const struct ls_stateful_record *ls_stateful_rec,
                                 "ip && ct.new && ct.trk"
                                 " && "REGBIT_HAIRPIN " == 1",
                                 "ct_snat_to_vip; next;",
-                                &od->nbs->header_);
+                                &od->nbs->header_,
+                                lflow_ref);
 
         /* If packet needs to be hairpinned, for established sessions there
          * should already be an SNAT conntrack entry.
@@ -7956,13 +8054,15 @@  build_lb_hairpin(const struct ls_stateful_record *ls_stateful_rec,
                                 "ip && ct.est && ct.trk"
                                 " && "REGBIT_HAIRPIN " == 1",
                                 "ct_snat;",
-                                &od->nbs->header_);
+                                &od->nbs->header_,
+                                lflow_ref);
 
         /* For the reply of hairpinned traffic, snat the src ip to the VIP. */
         ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_NAT_HAIRPIN, 90,
                                 "ip && "REGBIT_HAIRPIN_REPLY " == 1",
                                 "ct_snat;",
-                                &od->nbs->header_);
+                                &od->nbs->header_,
+                                lflow_ref);
 
         /* Ingress Hairpin table.
         * - Priority 1: Packets that were SNAT-ed for hairpinning should be
@@ -7972,12 +8072,13 @@  build_lb_hairpin(const struct ls_stateful_record *ls_stateful_rec,
             lflows, od, S_SWITCH_IN_HAIRPIN, 1,
             "("REGBIT_HAIRPIN " == 1 || " REGBIT_HAIRPIN_REPLY " == 1)",
             "eth.dst <-> eth.src; outport = inport; flags.loopback = 1; "
-            "output;");
+            "output;", lflow_ref);
     }
 }
 
 static void
-build_vtep_hairpin(struct ovn_datapath *od, struct lflow_table *lflows)
+build_vtep_hairpin(struct ovn_datapath *od, struct lflow_table *lflows,
+                   struct lflow_ref *lflow_ref)
 {
     if (!od->has_vtep_lports) {
         /* There is no need in these flows if datapath has no vtep lports. */
@@ -7990,7 +8091,7 @@  build_vtep_hairpin(struct ovn_datapath *od, struct lflow_table *lflows)
     char *action = xasprintf("next(pipeline=ingress, table=%d);",
                              ovn_stage_get_table(S_SWITCH_IN_L2_LKUP));
     ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 1000,
-                  REGBIT_FROM_RAMP" == 1", action);
+                  REGBIT_FROM_RAMP" == 1", action, lflow_ref);
     free(action);
 
     /* Ingress pre-arp flow for traffic from VTEP (ramp) switch.
@@ -8007,7 +8108,7 @@  build_vtep_hairpin(struct ovn_datapath *od, struct lflow_table *lflows)
                           REGBIT_FROM_RAMP" == 1 && is_chassis_resident(%s)",
                           op->cr_port->json_key);
             ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 2000,
-                          ds_cstr(&match), "next;");
+                          ds_cstr(&match), "next;", lflow_ref);
         }
     }
 
@@ -8018,14 +8119,15 @@  build_vtep_hairpin(struct ovn_datapath *od, struct lflow_table *lflows)
      */
     ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 65535,
                   REGBIT_FROM_RAMP" == 1 && (arp || nd_ns)",
-                  "flags.loopback = 1; next;");
+                  "flags.loopback = 1; next;", lflow_ref);
 
     ds_destroy(&match);
 }
 
 /* Build logical flows for the forwarding groups */
 static void
-build_fwd_group_lflows(struct ovn_datapath *od, struct lflow_table *lflows)
+build_fwd_group_lflows(struct ovn_datapath *od, struct lflow_table *lflows,
+                       struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbs);
     if (!od->nbs->n_forwarding_groups) {
@@ -8060,7 +8162,7 @@  build_fwd_group_lflows(struct ovn_datapath *od, struct lflow_table *lflows)
 
         ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 50,
                                 ds_cstr(&match), ds_cstr(&actions),
-                                &fwd_group->header_);
+                                &fwd_group->header_, lflow_ref);
 
         /* L2 lookup for the forwarding group's virtual MAC */
         ds_clear(&match);
@@ -8083,7 +8185,7 @@  build_fwd_group_lflows(struct ovn_datapath *od, struct lflow_table *lflows)
         ds_put_format(&actions, "fwd_group(%s);", ds_cstr(&group_ports));
         ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP, 50,
                                 ds_cstr(&match), ds_cstr(&actions),
-                                &fwd_group->header_);
+                                &fwd_group->header_, lflow_ref);
     }
 
     ds_destroy(&match);
@@ -8231,10 +8333,8 @@  build_lswitch_rport_arp_req_self_orig_flow(struct ovn_port *op,
     ds_put_format(&match,
                   "eth.src == %s && (arp.op == 1 || rarp.op == 3 || nd_ns)",
                   ds_cstr(&eth_src));
-    ovn_lflow_add_with_lflow_ref(lflows, od, S_SWITCH_IN_L2_LKUP, priority,
-                                 ds_cstr(&match),
-                                 "outport = \""MC_FLOOD_L2"\"; output;",
-                                 lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, priority, ds_cstr(&match),
+                  "outport = \""MC_FLOOD_L2"\"; output;", lflow_ref);
 
     ds_destroy(&eth_src);
     ds_destroy(&match);
@@ -8318,17 +8418,17 @@  build_lswitch_rport_arp_req_flow(const char *ips,
         ds_put_format(&actions, "clone {outport = %s; output; }; "
                                 "outport = \""MC_FLOOD_L2"\"; output;",
                       patch_op->json_key);
-        ovn_lflow_add_with_lflow_ref_hint(lflows, od, S_SWITCH_IN_L2_LKUP,
-                                          priority, ds_cstr(&match),
-                                          ds_cstr(&actions), stage_hint,
-                                          lflow_ref);
+        ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP,
+                                priority, ds_cstr(&match),
+                                ds_cstr(&actions), stage_hint,
+                                lflow_ref);
     } else {
         ds_put_format(&actions, "outport = %s; output;", patch_op->json_key);
-        ovn_lflow_add_with_lflow_ref_hint(lflows, od, S_SWITCH_IN_L2_LKUP,
-                                          priority, ds_cstr(&match),
-                                          ds_cstr(&actions),
-                                          stage_hint,
-                                          lflow_ref);
+        ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP,
+                                priority, ds_cstr(&match),
+                                ds_cstr(&actions),
+                                stage_hint,
+                                lflow_ref);
     }
 
     ds_destroy(&match);
@@ -8484,7 +8584,8 @@  build_dhcpv4_options_flows(struct ovn_port *op,
                            struct lport_addresses *lsp_addrs,
                            struct ovn_port *inport, bool is_external,
                            const struct shash *meter_groups,
-                           struct lflow_table *lflows)
+                           struct lflow_table *lflows,
+                           struct lflow_ref *lflow_ref)
 {
     struct ds match = DS_EMPTY_INITIALIZER;
 
@@ -8515,7 +8616,7 @@  build_dhcpv4_options_flows(struct ovn_port *op,
                               op->json_key);
             }
 
-            ovn_lflow_add_with_lflow_ref_hint__(lflows, op->od,
+            ovn_lflow_add_with_hint__(lflows, op->od,
                                       S_SWITCH_IN_DHCP_OPTIONS, 100,
                                       ds_cstr(&match),
                                       ds_cstr(&options_action),
@@ -8524,7 +8625,7 @@  build_dhcpv4_options_flows(struct ovn_port *op,
                                                      op->od->nbs->copp,
                                                      meter_groups),
                                       &op->nbsp->dhcpv4_options->header_,
-                                      op->lflow_ref);
+                                      lflow_ref);
             ds_clear(&match);
 
             /* If REGBIT_DHCP_OPTS_RESULT is set, it means the
@@ -8544,7 +8645,7 @@  build_dhcpv4_options_flows(struct ovn_port *op,
                 lflows, op->od, S_SWITCH_IN_DHCP_RESPONSE, 100,
                 ds_cstr(&match), ds_cstr(&response_action), inport->key,
                 &op->nbsp->dhcpv4_options->header_,
-                op->lflow_ref);
+                lflow_ref);
             ds_destroy(&options_action);
             ds_destroy(&response_action);
             ds_destroy(&ipv4_addr_match);
@@ -8572,7 +8673,7 @@  build_dhcpv4_options_flows(struct ovn_port *op,
                     lflows, op->od, S_SWITCH_OUT_ACL_EVAL, 34000,
                     ds_cstr(&match),dhcp_actions, op->key,
                     &op->nbsp->dhcpv4_options->header_,
-                    op->lflow_ref);
+                    lflow_ref);
             }
             break;
         }
@@ -8585,7 +8686,8 @@  build_dhcpv6_options_flows(struct ovn_port *op,
                            struct lport_addresses *lsp_addrs,
                            struct ovn_port *inport, bool is_external,
                            const struct shash *meter_groups,
-                           struct lflow_table *lflows)
+                           struct lflow_table *lflows,
+                           struct lflow_ref *lflow_ref)
 {
     struct ds match = DS_EMPTY_INITIALIZER;
 
@@ -8607,7 +8709,7 @@  build_dhcpv6_options_flows(struct ovn_port *op,
                               op->json_key);
             }
 
-            ovn_lflow_add_with_lflow_ref_hint__(lflows, op->od,
+            ovn_lflow_add_with_hint__(lflows, op->od,
                                       S_SWITCH_IN_DHCP_OPTIONS, 100,
                                       ds_cstr(&match),
                                       ds_cstr(&options_action),
@@ -8616,7 +8718,7 @@  build_dhcpv6_options_flows(struct ovn_port *op,
                                                      op->od->nbs->copp,
                                                      meter_groups),
                                       &op->nbsp->dhcpv6_options->header_,
-                                      op->lflow_ref);
+                                      lflow_ref);
 
             /* If REGBIT_DHCP_OPTS_RESULT is set to 1, it means the
              * put_dhcpv6_opts action is successful */
@@ -8624,7 +8726,7 @@  build_dhcpv6_options_flows(struct ovn_port *op,
             ovn_lflow_add_with_lport_and_hint(
                 lflows, op->od, S_SWITCH_IN_DHCP_RESPONSE, 100,
                 ds_cstr(&match), ds_cstr(&response_action), inport->key,
-                &op->nbsp->dhcpv6_options->header_, op->lflow_ref);
+                &op->nbsp->dhcpv6_options->header_, lflow_ref);
             ds_destroy(&options_action);
             ds_destroy(&response_action);
 
@@ -8657,7 +8759,7 @@  build_dhcpv6_options_flows(struct ovn_port *op,
                     lflows, op->od, S_SWITCH_OUT_ACL_EVAL, 34000,
                     ds_cstr(&match),dhcp6_actions, op->key,
                     &op->nbsp->dhcpv6_options->header_,
-                    op->lflow_ref);
+                    lflow_ref);
             }
             break;
         }
@@ -8668,7 +8770,8 @@  build_dhcpv6_options_flows(struct ovn_port *op,
 static void
 build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op,
                                                  const struct ovn_port *port,
-                                                 struct lflow_table *lflows)
+                                                 struct lflow_table *lflows,
+                                                 struct lflow_ref *lflow_ref)
 {
     struct ds match = DS_EMPTY_INITIALIZER;
 
@@ -8688,7 +8791,7 @@  build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op,
                     ovn_lflow_add_with_lport_and_hint(
                         lflows, op->od, S_SWITCH_IN_EXTERNAL_PORT, 100,
                         ds_cstr(&match),  debug_drop_action(), port->key,
-                        &op->nbsp->header_, op->lflow_ref);
+                        &op->nbsp->header_, lflow_ref);
                 }
                 for (size_t l = 0; l < rp->lsp_addrs[k].n_ipv6_addrs; l++) {
                     ds_clear(&match);
@@ -8704,7 +8807,7 @@  build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op,
                     ovn_lflow_add_with_lport_and_hint(
                         lflows, op->od, S_SWITCH_IN_EXTERNAL_PORT, 100,
                         ds_cstr(&match), debug_drop_action(), port->key,
-                        &op->nbsp->header_, op->lflow_ref);
+                        &op->nbsp->header_, lflow_ref);
                 }
 
                 ds_clear(&match);
@@ -8721,7 +8824,7 @@  build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op,
                                                   debug_drop_action(),
                                                   port->key,
                                                   &op->nbsp->header_,
-                                                  op->lflow_ref);
+                                                  lflow_ref);
             }
         }
     }
@@ -8736,19 +8839,22 @@  is_vlan_transparent(const struct ovn_datapath *od)
 
 static void
 build_lswitch_lflows_l2_unknown(struct ovn_datapath *od,
-                                struct lflow_table *lflows)
+                                struct lflow_table *lflows,
+                                struct lflow_ref *lflow_ref)
 {
     /* Ingress table 25/26: Destination lookup for unknown MACs. */
     if (od->has_unknown) {
         ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 50,
                       "outport == \"none\"",
-                      "outport = \""MC_UNKNOWN "\"; output;");
+                      "outport = \""MC_UNKNOWN "\"; output;",
+                      lflow_ref);
     } else {
         ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 50,
-                      "outport == \"none\"",  debug_drop_action());
+                      "outport == \"none\"",  debug_drop_action(),
+                      lflow_ref);
     }
     ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 0, "1",
-                  "output;");
+                  "output;", lflow_ref);
 }
 
 /* Build pre-ACL and ACL tables for both ingress and egress.
@@ -8758,42 +8864,49 @@  build_lswitch_lflows_pre_acl_and_acl(
     struct ovn_datapath *od,
     const struct chassis_features *features,
     struct lflow_table *lflows,
-    const struct shash *meter_groups)
+    const struct shash *meter_groups,
+    struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbs);
-    build_pre_acls(od, lflows);
-    build_pre_lb(od, meter_groups, lflows);
-    build_pre_stateful(od, features, lflows);
-    build_qos(od, lflows);
-    build_stateful(od, features, lflows);
-    build_vtep_hairpin(od, lflows);
+    build_pre_acls(od, lflows, lflow_ref);
+    build_pre_lb(od, meter_groups, lflows, lflow_ref);
+    build_pre_stateful(od, features, lflows, lflow_ref);
+    build_qos(od, lflows, lflow_ref);
+    build_stateful(od, features, lflows, lflow_ref);
+    build_vtep_hairpin(od, lflows, lflow_ref);
 }
 
 /* Logical switch ingress table 0: Admission control framework (priority
  * 100). */
 static void
 build_lswitch_lflows_admission_control(struct ovn_datapath *od,
-                                       struct lflow_table *lflows)
+                                       struct lflow_table *lflows,
+                                       struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbs);
     /* Logical VLANs not supported. */
     if (!is_vlan_transparent(od)) {
         /* Block logical VLANs. */
         ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 100,
-                      "vlan.present", debug_drop_action());
+                      "vlan.present", debug_drop_action(),
+                      lflow_ref);
     }
 
     /* Broadcast/multicast source address is invalid. */
     ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 100,
-                  "eth.src[40]", debug_drop_action());
+                  "eth.src[40]", debug_drop_action(),
+                  lflow_ref);
 
     ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 50, "1",
-                  REGBIT_PORT_SEC_DROP" = check_in_port_sec(); next;");
+                  REGBIT_PORT_SEC_DROP" = check_in_port_sec(); next;",
+                  lflow_ref);
 
     ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 50,
-                  REGBIT_PORT_SEC_DROP" == 1", debug_drop_action());
+                  REGBIT_PORT_SEC_DROP" == 1", debug_drop_action(),
+                  lflow_ref);
 
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 0, "1", "next;",
+                  lflow_ref);
 }
 
 /* Ingress table 19: ARP/ND responder, skip requests coming from localnet
@@ -8950,12 +9063,12 @@  build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op,
                     "output;",
                     op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s,
                     op->lsp_addrs[i].ipv4_addrs[j].addr_s);
-                ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
-                                                  S_SWITCH_IN_ARP_ND_RSP, 50,
-                                                  ds_cstr(match),
-                                                  ds_cstr(actions),
-                                                  &op->nbsp->header_,
-                                                  op->lflow_ref);
+                ovn_lflow_add_with_hint(lflows, op->od,
+                                        S_SWITCH_IN_ARP_ND_RSP, 50,
+                                        ds_cstr(match),
+                                        ds_cstr(actions),
+                                        &op->nbsp->header_,
+                                        op->lflow_ref);
 
                 /* Do not reply to an ARP request from the port that owns
                  * the address (otherwise a DHCP client that ARPs to check
@@ -9005,16 +9118,16 @@  build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op,
                         op->lsp_addrs[i].ipv6_addrs[j].addr_s,
                         op->lsp_addrs[i].ipv6_addrs[j].addr_s,
                         op->lsp_addrs[i].ea_s);
-                ovn_lflow_add_with_lflow_ref_hint__(lflows, op->od,
-                                                    S_SWITCH_IN_ARP_ND_RSP, 50,
-                                                    ds_cstr(match),
-                                                    ds_cstr(actions),
-                                                    NULL,
-                                                    copp_meter_get(COPP_ND_NA,
-                                                        op->od->nbs->copp,
-                                                        meter_groups),
-                                                    &op->nbsp->header_,
-                                                    op->lflow_ref);
+                ovn_lflow_add_with_hint__(lflows, op->od,
+                                          S_SWITCH_IN_ARP_ND_RSP, 50,
+                                          ds_cstr(match),
+                                          ds_cstr(actions),
+                                          NULL,
+                                          copp_meter_get(COPP_ND_NA,
+                                            op->od->nbs->copp,
+                                            meter_groups),
+                                          &op->nbsp->header_,
+                                          op->lflow_ref);
 
                 /* Do not reply to a solicitation from the port that owns
                  * the address (otherwise DAD detection will fail). */
@@ -9070,12 +9183,12 @@  build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op,
                 ea_s,
                 ea_s);
 
-            ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
-                                              S_SWITCH_IN_ARP_ND_RSP,
-                                              30, ds_cstr(match),
-                                              ds_cstr(actions),
-                                              &op->nbsp->header_,
-                                              op->lflow_ref);
+            ovn_lflow_add_with_hint(lflows, op->od,
+                                    S_SWITCH_IN_ARP_ND_RSP,
+                                    30, ds_cstr(match),
+                                    ds_cstr(actions),
+                                    &op->nbsp->header_,
+                                    op->lflow_ref);
         }
 
         /* Add IPv6 NDP responses.
@@ -9118,16 +9231,16 @@  build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op,
                     lsp_is_router(op->nbsp) ? "nd_na_router" : "nd_na",
                     ea_s,
                     ea_s);
-            ovn_lflow_add_with_lflow_ref_hint__(lflows, op->od,
-                                                S_SWITCH_IN_ARP_ND_RSP, 30,
-                                                ds_cstr(match),
-                                                ds_cstr(actions),
-                                                NULL,
-                                                copp_meter_get(COPP_ND_NA,
-                                                    op->od->nbs->copp,
-                                                    meter_groups),
-                                                &op->nbsp->header_,
-                                                op->lflow_ref);
+            ovn_lflow_add_with_hint__(lflows, op->od,
+                                      S_SWITCH_IN_ARP_ND_RSP, 30,
+                                      ds_cstr(match),
+                                      ds_cstr(actions),
+                                      NULL,
+                                      copp_meter_get(COPP_ND_NA,
+                                        op->od->nbs->copp,
+                                        meter_groups),
+                                      &op->nbsp->header_,
+                                      op->lflow_ref);
             ds_destroy(&ip6_dst_match);
             ds_destroy(&nd_target_match);
         }
@@ -9138,10 +9251,12 @@  build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op,
  * (priority 0)*/
 static void
 build_lswitch_arp_nd_responder_default(struct ovn_datapath *od,
-                                       struct lflow_table *lflows)
+                                       struct lflow_table *lflows,
+                                       struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbs);
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 0, "1", "next;",
+                  lflow_ref);
 }
 
 /* Ingress table 19: ARP/ND responder for service monitor source ip.
@@ -9151,7 +9266,8 @@  build_lswitch_arp_nd_service_monitor(const struct ovn_northd_lb *lb,
                                      const struct hmap *ls_ports,
                                      struct lflow_table *lflows,
                                      struct ds *actions,
-                                     struct ds *match)
+                                     struct ds *match,
+                                     struct lflow_ref *lflow_ref)
 {
     for (size_t i = 0; i < lb->n_vips; i++) {
         struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[i];
@@ -9215,7 +9331,8 @@  build_lswitch_arp_nd_service_monitor(const struct ovn_northd_lb *lb,
                                     op->od,
                                     S_SWITCH_IN_ARP_ND_RSP, 110,
                                     ds_cstr(match), ds_cstr(actions),
-                                    &lb->nlb->header_);
+                                    &lb->nlb->header_,
+                                    lflow_ref);
         }
     }
 }
@@ -9255,19 +9372,19 @@  build_lswitch_dhcp_options_and_response(struct ovn_port *op,
                 build_dhcpv4_options_flows(
                     op, &op->lsp_addrs[i],
                     op->od->localnet_ports[j], is_external,
-                    meter_groups, lflows);
+                    meter_groups, lflows, op->lflow_ref);
                 build_dhcpv6_options_flows(
                     op, &op->lsp_addrs[i],
                     op->od->localnet_ports[j], is_external,
-                    meter_groups, lflows);
+                    meter_groups, lflows, op->lflow_ref);
             }
         } else {
             build_dhcpv4_options_flows(op, &op->lsp_addrs[i], op,
                                        is_external, meter_groups,
-                                       lflows);
+                                       lflows, op->lflow_ref);
             build_dhcpv6_options_flows(op, &op->lsp_addrs[i], op,
                                        is_external, meter_groups,
-                                       lflows);
+                                       lflows, op->lflow_ref);
         }
     }
 }
@@ -9280,14 +9397,20 @@  build_lswitch_dhcp_options_and_response(struct ovn_port *op,
  * (priority 0). */
 static void
 build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od,
-                                        struct lflow_table *lflows)
+                                    struct lflow_table *lflows,
+                                    struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbs);
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_OPTIONS, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_RESPONSE, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_EXTERNAL_PORT, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_OPTIONS, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_RESPONSE, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_EXTERNAL_PORT, 0, "1", "next;",
+                  lflow_ref);
 }
 
 /* Logical switch ingress table 22 and 23: DNS lookup and response
@@ -9296,7 +9419,8 @@  build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od,
 static void
 build_lswitch_dns_lookup_and_response(struct ovn_datapath *od,
                                       struct lflow_table *lflows,
-                                      const struct shash *meter_groups)
+                                      const struct shash *meter_groups,
+                                      struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbs);
     if (!ls_has_dns_records(od->nbs)) {
@@ -9306,18 +9430,18 @@  build_lswitch_dns_lookup_and_response(struct ovn_datapath *od,
                       "udp.dst == 53",
                       REGBIT_DNS_LOOKUP_RESULT" = dns_lookup(); next;",
                       copp_meter_get(COPP_DNS, od->nbs->copp,
-                                     meter_groups));
+                                     meter_groups), lflow_ref);
     const char *dns_action = "eth.dst <-> eth.src; ip4.src <-> ip4.dst; "
                   "udp.dst = udp.src; udp.src = 53; outport = inport; "
                   "flags.loopback = 1; output;";
     const char *dns_match = "udp.dst == 53 && "REGBIT_DNS_LOOKUP_RESULT;
     ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 100,
-                  dns_match, dns_action);
+                  dns_match, dns_action, lflow_ref);
     dns_action = "eth.dst <-> eth.src; ip6.src <-> ip6.dst; "
                   "udp.dst = udp.src; udp.src = 53; outport = inport; "
                   "flags.loopback = 1; output;";
     ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 100,
-                  dns_match, dns_action);
+                  dns_match, dns_action, lflow_ref);
 }
 
 /* Table 24: External port. Drop ARP request for router ips from
@@ -9334,7 +9458,8 @@  build_lswitch_external_port(struct ovn_port *op,
     }
     for (size_t i = 0; i < op->od->n_localnet_ports; i++) {
         build_drop_arp_nd_flows_for_unbound_router_ports(
-            op, op->od->localnet_ports[i], lflows);
+            op, op->od->localnet_ports[i], lflows,
+            op->lflow_ref);
     }
 }
 
@@ -9344,7 +9469,8 @@  static void
 build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
                                         struct lflow_table *lflows,
                                         struct ds *actions,
-                                        const struct shash *meter_groups)
+                                        const struct shash *meter_groups,
+                                        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbs);
 
@@ -9352,7 +9478,7 @@  build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
                       "eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)",
                       "handle_svc_check(inport);",
                       copp_meter_get(COPP_SVC_MONITOR, od->nbs->copp,
-                                     meter_groups));
+                                     meter_groups), lflow_ref);
 
     struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw;
 
@@ -9363,27 +9489,31 @@  build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
         ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
                           "igmp", ds_cstr(actions),
                           copp_meter_get(COPP_IGMP, od->nbs->copp,
-                                         meter_groups));
+                                         meter_groups),
+                          lflow_ref);
 
         /* Punt MLD traffic to controller. */
         ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
                           "mldv1 || mldv2", ds_cstr(actions),
                           copp_meter_get(COPP_IGMP, od->nbs->copp,
-                                         meter_groups));
+                                         meter_groups),
+                          lflow_ref);
 
         /* Flood all IP multicast traffic destined to 224.0.0.X to all
          * ports - RFC 4541, section 2.1.2, item 2.
          */
         ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 85,
                       "ip4.mcast && ip4.dst == 224.0.0.0/24",
-                      "outport = \""MC_FLOOD_L2"\"; output;");
+                      "outport = \""MC_FLOOD_L2"\"; output;",
+                      lflow_ref);
 
         /* Flood all IPv6 multicast traffic destined to reserved
          * multicast IPs (RFC 4291, 2.7.1).
          */
         ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 85,
                       "ip6.mcast_flood",
-                      "outport = \""MC_FLOOD"\"; output;");
+                      "outport = \""MC_FLOOD"\"; output;",
+                      lflow_ref);
 
         /* Forward uregistered IP multicast to routers with relay enabled
          * and to any ports configured to flood IP multicast traffic.
@@ -9415,7 +9545,7 @@  build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
 
             ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80,
                           "ip4.mcast || ip6.mcast",
-                          ds_cstr(actions));
+                          ds_cstr(actions), lflow_ref);
         }
     }
 
@@ -9423,11 +9553,12 @@  build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
                        "broadcast-arps-to-all-routers", true)) {
         ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 72,
                       "eth.mcast && (arp.op == 1 || nd_ns)",
-                      "outport = \""MC_FLOOD_L2"\"; output;");
+                      "outport = \""MC_FLOOD_L2"\"; output;",
+                      lflow_ref);
     }
 
     ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 70, "eth.mcast",
-                  "outport = \""MC_FLOOD"\"; output;");
+                  "outport = \""MC_FLOOD"\"; output;", lflow_ref);
 }
 
 
@@ -9437,7 +9568,8 @@  static void
 build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group,
                                 struct lflow_table *lflows,
                                 struct ds *actions,
-                                struct ds *match)
+                                struct ds *match,
+                                struct lflow_ref *lflow_ref)
 {
     uint64_t dummy;
 
@@ -9509,7 +9641,7 @@  build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group,
                       igmp_group->mcgroup.name);
 
         ovn_lflow_add(lflows, igmp_group->datapath, S_SWITCH_IN_L2_LKUP,
-                      90, ds_cstr(match), ds_cstr(actions));
+                      90, ds_cstr(match), ds_cstr(actions), lflow_ref);
     }
 }
 
@@ -9549,12 +9681,12 @@  build_lswitch_ip_unicast_lookup(struct ovn_port *op,
 
             ds_clear(actions);
             ds_put_format(actions, action, op->json_key);
-            ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
-                                              S_SWITCH_IN_L2_LKUP,
-                                              50, ds_cstr(match),
-                                              ds_cstr(actions),
-                                              &op->nbsp->header_,
-                                              op->lflow_ref);
+            ovn_lflow_add_with_hint(lflows, op->od,
+                                    S_SWITCH_IN_L2_LKUP,
+                                    50, ds_cstr(match),
+                                    ds_cstr(actions),
+                                    &op->nbsp->header_,
+                                    op->lflow_ref);
         } else if (!strcmp(op->nbsp->addresses[i], "unknown")) {
             continue;
         } else if (is_dynamic_lsp_address(op->nbsp->addresses[i])) {
@@ -9569,12 +9701,12 @@  build_lswitch_ip_unicast_lookup(struct ovn_port *op,
 
             ds_clear(actions);
             ds_put_format(actions, action, op->json_key);
-            ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
-                                              S_SWITCH_IN_L2_LKUP,
-                                              50, ds_cstr(match),
-                                              ds_cstr(actions),
-                                              &op->nbsp->header_,
-                                              op->lflow_ref);
+            ovn_lflow_add_with_hint(lflows, op->od,
+                                    S_SWITCH_IN_L2_LKUP,
+                                    50, ds_cstr(match),
+                                    ds_cstr(actions),
+                                    &op->nbsp->header_,
+                                    op->lflow_ref);
         } else if (!strcmp(op->nbsp->addresses[i], "router")) {
             if (!op->peer || !op->peer->nbrp
                 || !ovs_scan(op->peer->nbrp->mac,
@@ -9626,11 +9758,11 @@  build_lswitch_ip_unicast_lookup(struct ovn_port *op,
 
             ds_clear(actions);
             ds_put_format(actions, action, op->json_key);
-            ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
-                                              S_SWITCH_IN_L2_LKUP, 50,
-                                              ds_cstr(match), ds_cstr(actions),
-                                              &op->nbsp->header_,
-                                              op->lflow_ref);
+            ovn_lflow_add_with_hint(lflows, op->od,
+                                    S_SWITCH_IN_L2_LKUP, 50,
+                                    ds_cstr(match), ds_cstr(actions),
+                                    &op->nbsp->header_,
+                                    op->lflow_ref);
         } else {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
 
@@ -9678,7 +9810,7 @@  build_lswitch_ip_unicast_lookup_for_nats(struct ovn_port *op,
 
             ds_clear(actions);
             ds_put_format(actions, action, op->json_key);
-            ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
+            ovn_lflow_add_with_hint(lflows, op->od,
                                     S_SWITCH_IN_L2_LKUP, 50,
                                     ds_cstr(match),
                                     ds_cstr(actions),
@@ -9926,7 +10058,8 @@  static void
 build_routing_policy_flow(struct lflow_table *lflows, struct ovn_datapath *od,
                           const struct hmap *lr_ports,
                           const struct nbrec_logical_router_policy *rule,
-                          const struct ovsdb_idl_row *stage_hint)
+                          const struct ovsdb_idl_row *stage_hint,
+                          struct lflow_ref *lflow_ref)
 {
     struct ds match = DS_EMPTY_INITIALIZER;
     struct ds actions = DS_EMPTY_INITIALIZER;
@@ -9982,7 +10115,8 @@  build_routing_policy_flow(struct lflow_table *lflows, struct ovn_datapath *od,
     ds_put_format(&match, "%s", rule->match);
 
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY, rule->priority,
-                            ds_cstr(&match), ds_cstr(&actions), stage_hint);
+                            ds_cstr(&match), ds_cstr(&actions), stage_hint,
+                            lflow_ref);
     ds_destroy(&match);
     ds_destroy(&actions);
 }
@@ -9992,7 +10126,8 @@  build_ecmp_routing_policy_flows(struct lflow_table *lflows,
                                 struct ovn_datapath *od,
                                 const struct hmap *lr_ports,
                                 const struct nbrec_logical_router_policy *rule,
-                                uint16_t ecmp_group_id)
+                                uint16_t ecmp_group_id,
+                                struct lflow_ref *lflow_ref)
 {
     ovs_assert(rule->n_nexthops > 1);
 
@@ -10064,7 +10199,8 @@  build_ecmp_routing_policy_flows(struct lflow_table *lflows,
                       ecmp_group_id, i + 1);
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY_ECMP,
                                 100, ds_cstr(&match),
-                                ds_cstr(&actions), &rule->header_);
+                                ds_cstr(&actions), &rule->header_,
+                                lflow_ref);
     }
 
     ds_clear(&actions);
@@ -10082,7 +10218,8 @@  build_ecmp_routing_policy_flows(struct lflow_table *lflows,
     ds_put_cstr(&actions, ");");
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY,
                             rule->priority, rule->match,
-                            ds_cstr(&actions), &rule->header_);
+                            ds_cstr(&actions), &rule->header_,
+                            lflow_ref);
 
 cleanup:
     ds_destroy(&match);
@@ -10127,7 +10264,8 @@  get_route_table_id(struct simap *route_tables, const char *route_table_name)
 static void
 build_route_table_lflow(struct ovn_datapath *od, struct lflow_table *lflows,
                         struct nbrec_logical_router_port *lrp,
-                        struct simap *route_tables)
+                        struct simap *route_tables,
+                        struct lflow_ref *lflow_ref)
 {
     struct ds match = DS_EMPTY_INITIALIZER;
     struct ds actions = DS_EMPTY_INITIALIZER;
@@ -10143,7 +10281,7 @@  build_route_table_lflow(struct ovn_datapath *od, struct lflow_table *lflows,
                   REG_ROUTE_TABLE_ID, rtb_id);
 
     ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_PRE, 100,
-                  ds_cstr(&match), ds_cstr(&actions));
+                  ds_cstr(&match), ds_cstr(&actions), lflow_ref);
 
     ds_destroy(&match);
     ds_destroy(&actions);
@@ -10542,7 +10680,8 @@  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
                                const char *port_ip,
                                struct ovn_port *out_port,
                                const struct parsed_route *route,
-                               struct ds *route_match)
+                               struct ds *route_match,
+                               struct lflow_ref *lflow_ref)
 {
     const struct nbrec_logical_router_static_route *st_route = route->route;
     struct ds base_match = DS_EMPTY_INITIALIZER;
@@ -10565,12 +10704,12 @@  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
     free(cidr);
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, 100,
                              ds_cstr(&base_match), "ct_next;",
-                             &st_route->header_);
+                             &st_route->header_, lflow_ref);
 
     /* And packets that go out over an ECMP route need conntrack */
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, 100,
                              ds_cstr(route_match), "ct_next;",
-                             &st_route->header_);
+                             &st_route->header_, lflow_ref);
 
     /* Save src eth and inport in ct_label for packets that arrive over
      * an ECMP route.
@@ -10587,7 +10726,8 @@  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
             ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
                             ds_cstr(&match), ds_cstr(&actions),
-                            &st_route->header_);
+                            &st_route->header_,
+                            lflow_ref);
     ds_clear(&match);
     ds_put_format(&match, "%s && (ct.new && !ct.est) && udp",
                   ds_cstr(&base_match));
@@ -10599,7 +10739,8 @@  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
             ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
                             ds_cstr(&match), ds_cstr(&actions),
-                            &st_route->header_);
+                            &st_route->header_,
+                            lflow_ref);
     ds_clear(&match);
     ds_put_format(&match, "%s && (ct.new && !ct.est) && sctp",
                   ds_cstr(&base_match));
@@ -10611,7 +10752,8 @@  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
             ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
                             ds_cstr(&match), ds_cstr(&actions),
-                            &st_route->header_);
+                            &st_route->header_,
+                            lflow_ref);
 
     ds_clear(&match);
     ds_put_format(&match,
@@ -10625,7 +10767,8 @@  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
             ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
                             ds_cstr(&match), ds_cstr(&actions),
-                            &st_route->header_);
+                            &st_route->header_,
+                            lflow_ref);
 
     ds_clear(&match);
     ds_put_format(&match,
@@ -10639,7 +10782,8 @@  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
             ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
                             ds_cstr(&match), ds_cstr(&actions),
-                            &st_route->header_);
+                            &st_route->header_,
+                            lflow_ref);
     ds_clear(&match);
     ds_put_format(&match,
             "%s && (!ct.rpl && ct.est) && sctp",
@@ -10652,7 +10796,8 @@  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
             ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
                             ds_cstr(&match), ds_cstr(&actions),
-                            &st_route->header_);
+                            &st_route->header_,
+                            lflow_ref);
 
     /* Bypass ECMP selection if we already have ct_label information
      * for where to route the packet.
@@ -10671,12 +10816,14 @@  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
                   port_ip, out_port->json_key);
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING, 10300,
                            ds_cstr(&match), ds_cstr(&actions),
-                           &st_route->header_);
+                           &st_route->header_,
+                           lflow_ref);
 
     /* Egress reply traffic for symmetric ECMP routes skips router policies. */
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY, 65535,
                             ds_cstr(&ecmp_reply), "next;",
-                            &st_route->header_);
+                            &st_route->header_,
+                            lflow_ref);
 
     /* Use REG_ECMP_ETH_FULL to pass the eth field from ct_label to eth.dst to
      * avoid masked access to ct_label. Otherwise it may prevent OVS flow
@@ -10692,7 +10839,8 @@  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
                          " pop(" REG_ECMP_ETH_FULL "); next;";
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ARP_RESOLVE,
                             200, ds_cstr(&ecmp_reply),
-                            action, &st_route->header_);
+                            action, &st_route->header_,
+                            lflow_ref);
 
     ds_destroy(&base_match);
     ds_destroy(&match);
@@ -10703,7 +10851,8 @@  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
 static void
 build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od,
                       bool ct_masked_mark, const struct hmap *lr_ports,
-                      struct ecmp_groups_node *eg)
+                      struct ecmp_groups_node *eg,
+                      struct lflow_ref *lflow_ref)
 
 {
     bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&eg->prefix);
@@ -10736,7 +10885,8 @@  build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od,
     ds_put_cstr(&actions, ");");
 
     ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, priority,
-                  ds_cstr(&route_match), ds_cstr(&actions));
+                  ds_cstr(&route_match), ds_cstr(&actions),
+                  lflow_ref);
 
     /* Add per member flow */
     struct ds match = DS_EMPTY_INITIALIZER;
@@ -10759,7 +10909,8 @@  build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od,
                                                      out_port->key)) {
             add_ecmp_symmetric_reply_flows(lflows, od, ct_masked_mark,
                                            lrp_addr_s, out_port,
-                                           route_, &route_match);
+                                           route_, &route_match,
+                                           lflow_ref);
         }
         ds_clear(&match);
         ds_put_format(&match, REG_ECMP_GROUP_ID" == %"PRIu16" && "
@@ -10779,7 +10930,7 @@  build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od,
                       out_port->json_key);
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 100,
                                 ds_cstr(&match), ds_cstr(&actions),
-                                &route->header_);
+                                &route->header_, lflow_ref);
     }
     sset_destroy(&visited_ports);
     ds_destroy(&match);
@@ -10836,17 +10987,17 @@  add_route(struct lflow_table *lflows, struct ovn_datapath *od,
         ds_put_format(&actions, "ip.ttl--; %s", ds_cstr(&common_actions));
     }
 
-    ovn_lflow_add_with_lflow_ref_hint(lflows, od, S_ROUTER_IN_IP_ROUTING,
-                                      priority, ds_cstr(&match),
-                                      ds_cstr(&actions), stage_hint,
-                                      lflow_ref);
+    ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING,
+                            priority, ds_cstr(&match),
+                            ds_cstr(&actions), stage_hint,
+                            lflow_ref);
     if (op && op->has_bfd) {
         ds_put_format(&match, " && udp.dst == 3784");
-        ovn_lflow_add_with_lflow_ref_hint(lflows, op->od,
-                                          S_ROUTER_IN_IP_ROUTING,
-                                          priority + 1, ds_cstr(&match),
-                                          ds_cstr(&common_actions),\
-                                          stage_hint, lflow_ref);
+        ovn_lflow_add_with_hint(lflows, op->od,
+                                S_ROUTER_IN_IP_ROUTING,
+                                priority + 1, ds_cstr(&match),
+                                ds_cstr(&common_actions),\
+                                stage_hint, lflow_ref);
     }
     ds_destroy(&match);
     ds_destroy(&common_actions);
@@ -10856,7 +11007,8 @@  add_route(struct lflow_table *lflows, struct ovn_datapath *od,
 static void
 build_static_route_flow(struct lflow_table *lflows, struct ovn_datapath *od,
                         const struct hmap *lr_ports,
-                        const struct parsed_route *route_)
+                        const struct parsed_route *route_,
+                        struct lflow_ref *lflow_ref)
 {
     const char *lrp_addr_s = NULL;
     struct ovn_port *out_port = NULL;
@@ -10880,7 +11032,7 @@  build_static_route_flow(struct lflow_table *lflows, struct ovn_datapath *od,
     add_route(lflows, route_->is_discard_route ? od : out_port->od, out_port,
               lrp_addr_s, prefix_s, route_->plen, route->nexthop,
               route_->is_src_route, route_->route_table_id, &route->header_,
-              route_->is_discard_route, ofs, NULL);
+              route_->is_discard_route, ofs, lflow_ref);
 
     free(prefix_s);
 }
@@ -10956,7 +11108,8 @@  lrouter_use_common_zone(const struct ovn_datapath *od)
 static void
 build_distr_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx,
                                      enum lrouter_nat_lb_flow_type type,
-                                     struct ovn_datapath *od)
+                                     struct ovn_datapath *od,
+                                     struct lflow_ref *lflow_ref)
 {
     struct ovn_port *dgp = od->l3dgw_ports[0];
 
@@ -10995,7 +11148,8 @@  build_distr_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx,
 
     ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT, ctx->prio,
                               ds_cstr(ctx->new_match), ctx->new_action[type],
-                              NULL, meter, &ctx->lb->nlb->header_);
+                              NULL, meter, &ctx->lb->nlb->header_,
+                              lflow_ref);
 
     ds_truncate(ctx->new_match, new_match_len);
 
@@ -11014,7 +11168,8 @@  build_distr_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx,
     ovn_lflow_add_with_hint(ctx->lflows, od, S_ROUTER_IN_GW_REDIRECT,
                             200, ds_cstr(ctx->undnat_match),
                             ds_cstr(ctx->gw_redir_action),
-                            &ctx->lb->nlb->header_);
+                            &ctx->lb->nlb->header_,
+                            lflow_ref);
     ds_truncate(ctx->undnat_match, undnat_match_len);
 
     ds_put_format(ctx->undnat_match, ") && (inport == %s || outport == %s)"
@@ -11022,7 +11177,8 @@  build_distr_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx,
                   dgp->cr_port->json_key);
     ovn_lflow_add_with_hint(ctx->lflows, od, S_ROUTER_OUT_UNDNAT, 120,
                             ds_cstr(ctx->undnat_match), undnat_action,
-                            &ctx->lb->nlb->header_);
+                            &ctx->lb->nlb->header_,
+                            lflow_ref);
     ds_truncate(ctx->undnat_match, undnat_match_len);
 }
 
@@ -11030,7 +11186,8 @@  static void
 build_gw_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx,
                                   enum lrouter_nat_lb_flow_type type,
                                   const struct ovn_datapaths *lr_datapaths,
-                                  const unsigned long *dp_bitmap)
+                                  const unsigned long *dp_bitmap,
+                                  struct lflow_ref *lflow_ref)
 {
     unsigned long *dp_non_meter = NULL;
     bool build_non_meter = false;
@@ -11056,14 +11213,14 @@  build_gw_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx,
             bitmap_set0(dp_non_meter, index);
             ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT,
                     ctx->prio, ds_cstr(ctx->new_match), ctx->new_action[type],
-                    NULL, meter, &ctx->lb->nlb->header_);
+                    NULL, meter, &ctx->lb->nlb->header_, lflow_ref);
         }
     }
     if (!ctx->reject || build_non_meter) {
         ovn_lflow_add_with_dp_group(ctx->lflows,
             dp_non_meter ? dp_non_meter : dp_bitmap, ods_size(lr_datapaths),
             S_ROUTER_IN_DNAT, ctx->prio, ds_cstr(ctx->new_match),
-            ctx->new_action[type], &ctx->lb->nlb->header_);
+            ctx->new_action[type], &ctx->lb->nlb->header_, lflow_ref);
     }
     bitmap_free(dp_non_meter);
 }
@@ -11078,7 +11235,8 @@  build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
                                struct ds *match, struct ds *action,
                                const struct shash *meter_groups,
                                const struct chassis_features *features,
-                               const struct hmap *svc_monitor_map)
+                               const struct hmap *svc_monitor_map,
+                               struct lflow_ref *lflow_ref)
 {
     const struct ovn_northd_lb *lb = lb_dps->lb;
     bool ipv4 = lb_vip->address_family == AF_INET;
@@ -11196,7 +11354,7 @@  build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
         if (!od->n_l3dgw_ports) {
             bitmap_set1(gw_dp_bitmap[type], index);
         } else {
-            build_distr_lrouter_nat_flows_for_lb(&ctx, type, od);
+            build_distr_lrouter_nat_flows_for_lb(&ctx, type, od, lflow_ref);
         }
 
         if (lb->affinity_timeout) {
@@ -11217,16 +11375,17 @@  build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
              * S_ROUTER_IN_DNAT stage. */
             ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, 120,
                                     ds_cstr(&unsnat_match), "next;",
-                                    &lb->nlb->header_);
+                                    &lb->nlb->header_, lflow_ref);
         }
     }
 
     for (size_t type = 0; type < LROUTER_NAT_LB_FLOW_MAX; type++) {
         build_gw_lrouter_nat_flows_for_lb(&ctx, type, lr_datapaths,
-                                          gw_dp_bitmap[type]);
+                                          gw_dp_bitmap[type],
+                                          lflow_ref);
         build_lb_affinity_lr_flows(lflows, lb, lb_vip, ds_cstr(match),
                                    aff_action[type], aff_dp_bitmap[type],
-                                   lr_datapaths);
+                                   lr_datapaths, lflow_ref);
     }
 
     ds_destroy(&unsnat_match);
@@ -11248,7 +11407,8 @@  build_lswitch_flows_for_lb(struct ovn_lb_datapaths *lb_dps,
                            const struct ovn_datapaths *ls_datapaths,
                            const struct chassis_features *features,
                            const struct hmap *svc_monitor_map,
-                           struct ds *match, struct ds *action)
+                           struct ds *match, struct ds *action,
+                           struct lflow_ref *lflow_ref)
 {
     if (!lb_dps->n_nb_ls) {
         return;
@@ -11274,7 +11434,8 @@  build_lswitch_flows_for_lb(struct ovn_lb_datapaths *lb_dps,
                                       copp_meter_get(COPP_EVENT_ELB,
                                                      od->nbs->copp,
                                                      meter_groups),
-                                      &lb->nlb->header_);
+                                      &lb->nlb->header_,
+                                      lflow_ref);
         }
         /* Ignore L4 port information in the key because fragmented packets
          * may not have L4 information.  The pre-stateful table will send
@@ -11289,9 +11450,9 @@  build_lswitch_flows_for_lb(struct ovn_lb_datapaths *lb_dps,
      * connection, so it is okay if we do not hit the above match on
      * REGBIT_CONNTRACK_COMMIT. */
     build_lb_rules_pre_stateful(lflows, lb_dps, features->ct_no_masked_label,
-                                ls_datapaths, match, action);
+                                ls_datapaths, match, action, lflow_ref);
     build_lb_rules(lflows, lb_dps, ls_datapaths, features, match, action,
-                   meter_groups, svc_monitor_map);
+                   meter_groups, svc_monitor_map, lflow_ref);
 }
 
 /* If there are any load balancing rules, we should send the packet to
@@ -11306,7 +11467,8 @@  static void
 build_lrouter_defrag_flows_for_lb(struct ovn_lb_datapaths *lb_dps,
                                   struct lflow_table *lflows,
                                   const struct ovn_datapaths *lr_datapaths,
-                                  struct ds *match)
+                                  struct ds *match,
+                                  struct lflow_ref *lflow_ref)
 {
     if (!lb_dps->n_nb_lr) {
         return;
@@ -11324,7 +11486,7 @@  build_lrouter_defrag_flows_for_lb(struct ovn_lb_datapaths *lb_dps,
         ovn_lflow_add_with_dp_group(
             lflows, lb_dps->nb_lr_map, ods_size(lr_datapaths),
             S_ROUTER_IN_DEFRAG, prio, ds_cstr(match), "ct_dnat;",
-            &lb_dps->lb->nlb->header_);
+            &lb_dps->lb->nlb->header_, lflow_ref);
     }
 }
 
@@ -11336,7 +11498,8 @@  build_lrouter_flows_for_lb(struct ovn_lb_datapaths *lb_dps,
                            const struct lr_stateful_table *lr_sful_table,
                            const struct chassis_features *features,
                            const struct hmap *svc_monitor_map,
-                           struct ds *match, struct ds *action)
+                           struct ds *match, struct ds *action,
+                           struct lflow_ref *lflow_ref)
 {
     size_t index;
 
@@ -11351,7 +11514,7 @@  build_lrouter_flows_for_lb(struct ovn_lb_datapaths *lb_dps,
         build_lrouter_nat_flows_for_lb(lb_vip, lb_dps, &lb->vips_nb[i],
                                        lr_datapaths, lr_sful_table, lflows, match,
                                        action, meter_groups, features,
-                                       svc_monitor_map);
+                                       svc_monitor_map, lflow_ref);
 
         if (!build_empty_lb_event_flow(lb_vip, lb, match, action)) {
             continue;
@@ -11366,7 +11529,7 @@  build_lrouter_flows_for_lb(struct ovn_lb_datapaths *lb_dps,
                                       copp_meter_get(COPP_EVENT_ELB,
                                                      od->nbr->copp,
                                                      meter_groups),
-                                      &lb->nlb->header_);
+                                      &lb->nlb->header_, lflow_ref);
         }
     }
 
@@ -11375,7 +11538,8 @@  build_lrouter_flows_for_lb(struct ovn_lb_datapaths *lb_dps,
             struct ovn_datapath *od = lr_datapaths->array[index];
 
             ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 120,
-                          "flags.skip_snat_for_lb == 1 && ip", "next;");
+                          "flags.skip_snat_for_lb == 1 && ip", "next;",
+                          lflow_ref);
         }
     }
 }
@@ -11490,7 +11654,8 @@  static inline void
 lrouter_nat_add_ext_ip_match(const struct ovn_datapath *od,
                              struct lflow_table *lflows, struct ds *match,
                              const struct nbrec_nat *nat,
-                             bool is_v6, bool is_src, int cidr_bits)
+                             bool is_v6, bool is_src, int cidr_bits,
+                             struct lflow_ref *lflow_ref)
 {
     struct nbrec_address_set *allowed_ext_ips = nat->allowed_ext_ips;
     struct nbrec_address_set *exempted_ext_ips = nat->exempted_ext_ips;
@@ -11541,7 +11706,7 @@  lrouter_nat_add_ext_ip_match(const struct ovn_datapath *od,
 
         ovn_lflow_add_with_hint(lflows, od, stage, priority,
                                 ds_cstr(&match_exempt), "next;",
-                                &nat->header_);
+                                &nat->header_, lflow_ref);
         ds_destroy(&match_exempt);
     }
 }
@@ -11555,7 +11720,8 @@  build_lrouter_arp_flow(const struct ovn_datapath *od, struct ovn_port *op,
                        const char *ip_address, const char *eth_addr,
                        struct ds *extra_match, bool drop, uint16_t priority,
                        const struct ovsdb_idl_row *hint,
-                       struct lflow_table *lflows)
+                       struct lflow_table *lflows,
+                       struct lflow_ref *lflow_ref)
 {
     struct ds match = DS_EMPTY_INITIALIZER;
     struct ds actions = DS_EMPTY_INITIALIZER;
@@ -11587,7 +11753,8 @@  build_lrouter_arp_flow(const struct ovn_datapath *od, struct ovn_port *op,
     }
 
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority,
-                            ds_cstr(&match), ds_cstr(&actions), hint);
+                            ds_cstr(&match), ds_cstr(&actions), hint,
+                            lflow_ref);
 
     ds_destroy(&match);
     ds_destroy(&actions);
@@ -11606,7 +11773,8 @@  build_lrouter_nd_flow(const struct ovn_datapath *od, struct ovn_port *op,
                       struct ds *extra_match, bool drop, uint16_t priority,
                       const struct ovsdb_idl_row *hint,
                       struct lflow_table *lflows,
-                      const struct shash *meter_groups)
+                      const struct shash *meter_groups,
+                      struct lflow_ref *lflow_ref)
 {
     struct ds match = DS_EMPTY_INITIALIZER;
     struct ds actions = DS_EMPTY_INITIALIZER;
@@ -11629,7 +11797,8 @@  build_lrouter_nd_flow(const struct ovn_datapath *od, struct ovn_port *op,
     if (drop) {
         ds_put_cstr(&actions, debug_drop_action());
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority,
-                                ds_cstr(&match), ds_cstr(&actions), hint);
+                                ds_cstr(&match), ds_cstr(&actions), hint,
+                                lflow_ref);
     } else {
         ds_put_format(&actions,
                       "%s { "
@@ -11647,7 +11816,7 @@  build_lrouter_nd_flow(const struct ovn_datapath *od, struct ovn_port *op,
                                   ds_cstr(&match), ds_cstr(&actions), NULL,
                                   copp_meter_get(COPP_ND_NA, od->nbr->copp,
                                                  meter_groups),
-                                  hint);
+                                  hint, lflow_ref);
     }
 
     ds_destroy(&match);
@@ -11658,7 +11827,8 @@  static void
 build_lrouter_nat_arp_nd_flow(const struct ovn_datapath *od,
                               struct ovn_nat *nat_entry,
                               struct lflow_table *lflows,
-                              const struct shash *meter_groups)
+                              const struct shash *meter_groups,
+                              struct lflow_ref *lflow_ref)
 {
     struct lport_addresses *ext_addrs = &nat_entry->ext_addrs;
     const struct nbrec_nat *nat = nat_entry->nb;
@@ -11668,12 +11838,14 @@  build_lrouter_nat_arp_nd_flow(const struct ovn_datapath *od,
                               ext_addrs->ipv6_addrs[0].addr_s,
                               ext_addrs->ipv6_addrs[0].sn_addr_s,
                               REG_INPORT_ETH_ADDR, NULL, false, 90,
-                              &nat->header_, lflows, meter_groups);
+                              &nat->header_, lflows, meter_groups,
+                              lflow_ref);
     } else {
         build_lrouter_arp_flow(od, NULL,
                                ext_addrs->ipv4_addrs[0].addr_s,
                                REG_INPORT_ETH_ADDR, NULL, false, 90,
-                               &nat->header_, lflows);
+                               &nat->header_, lflows,
+                               lflow_ref);
     }
 }
 
@@ -11681,7 +11853,8 @@  static void
 build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op,
                                    struct ovn_nat *nat_entry,
                                    struct lflow_table *lflows,
-                                   const struct shash *meter_groups)
+                                   const struct shash *meter_groups,
+                                   struct lflow_ref *lflow_ref)
 {
     struct lport_addresses *ext_addrs = &nat_entry->ext_addrs;
     const struct nbrec_nat *nat = nat_entry->nb;
@@ -11729,21 +11902,25 @@  build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op,
                               ext_addrs->ipv6_addrs[0].addr_s,
                               ext_addrs->ipv6_addrs[0].sn_addr_s,
                               mac_s, &match, false, 92,
-                              &nat->header_, lflows, meter_groups);
+                              &nat->header_, lflows, meter_groups,
+                              lflow_ref);
         build_lrouter_nd_flow(op->od, op, "nd_na",
                               ext_addrs->ipv6_addrs[0].addr_s,
                               ext_addrs->ipv6_addrs[0].sn_addr_s,
                               mac_s, NULL, true, 91,
-                              &nat->header_, lflows, meter_groups);
+                              &nat->header_, lflows, meter_groups,
+                              lflow_ref);
     } else {
         build_lrouter_arp_flow(op->od, op,
                                ext_addrs->ipv4_addrs[0].addr_s,
                                mac_s, &match, false, 92,
-                               &nat->header_, lflows);
+                               &nat->header_, lflows,
+                               lflow_ref);
         build_lrouter_arp_flow(op->od, op,
                                ext_addrs->ipv4_addrs[0].addr_s,
                                mac_s, NULL, true, 91,
-                               &nat->header_, lflows);
+                               &nat->header_, lflows,
+                               lflow_ref);
     }
 
     ds_destroy(&match);
@@ -11754,7 +11931,8 @@  build_lrouter_drop_own_dest(struct ovn_port *op,
                             const struct lr_stateful_record *lr_sful_rec,
                             enum ovn_stage stage,
                             uint16_t priority, bool drop_snat_ip,
-                            struct lflow_table *lflows)
+                            struct lflow_table *lflows,
+                            struct lflow_ref *lflow_ref)
 {
     struct ds match_ips = DS_EMPTY_INITIALIZER;
 
@@ -11781,7 +11959,8 @@  build_lrouter_drop_own_dest(struct ovn_port *op,
             char *match = xasprintf("ip4.dst == {%s}", ds_cstr(&match_ips));
             ovn_lflow_add_with_hint(lflows, op->od, stage, priority,
                                     match, debug_drop_action(),
-                                    &op->nbrp->header_);
+                                    &op->nbrp->header_,
+                                    lflow_ref);
             free(match);
         }
     }
@@ -11811,7 +11990,8 @@  build_lrouter_drop_own_dest(struct ovn_port *op,
             char *match = xasprintf("ip6.dst == {%s}", ds_cstr(&match_ips));
             ovn_lflow_add_with_hint(lflows, op->od, stage, priority,
                                     match, debug_drop_action(),
-                                    &op->nbrp->header_);
+                                    &op->nbrp->header_,
+                                    lflow_ref);
             free(match);
         }
     }
@@ -11822,14 +12002,15 @@  static void
 build_lrouter_force_snat_flows(struct lflow_table *lflows,
                                const struct ovn_datapath *od,
                                const char *ip_version, const char *ip_addr,
-                               const char *context)
+                               const char *context,
+                               struct lflow_ref *lflow_ref)
 {
     struct ds match = DS_EMPTY_INITIALIZER;
     struct ds actions = DS_EMPTY_INITIALIZER;
     ds_put_format(&match, "ip%s && ip%s.dst == %s",
                   ip_version, ip_version, ip_addr);
     ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 110,
-                  ds_cstr(&match), "ct_snat;");
+                  ds_cstr(&match), "ct_snat;", lflow_ref);
 
     /* Higher priority rules to force SNAT with the IP addresses
      * configured in the Gateway router.  This only takes effect
@@ -11839,7 +12020,8 @@  build_lrouter_force_snat_flows(struct lflow_table *lflows,
                   context, ip_version);
     ds_put_format(&actions, "ct_snat(%s);", ip_addr);
     ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 100,
-                  ds_cstr(&match), ds_cstr(&actions));
+                  ds_cstr(&match), ds_cstr(&actions),
+                  lflow_ref);
 
     ds_destroy(&match);
     ds_destroy(&actions);
@@ -11849,7 +12031,8 @@  static void
 build_lrouter_force_snat_flows_op(struct ovn_port *op,
                                   const struct lr_nat_record *lrnat_rec,
                                   struct lflow_table *lflows,
-                                  struct ds *match, struct ds *actions)
+                                  struct ds *match, struct ds *actions,
+                                  struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbrp);
     if (!op->peer || !lrnat_rec->lb_force_snat_router_ip) {
@@ -11863,7 +12046,7 @@  build_lrouter_force_snat_flows_op(struct ovn_port *op,
         ds_put_format(match, "inport == %s && ip4.dst == %s",
                       op->json_key, op->lrp_networks.ipv4_addrs[0].addr_s);
         ovn_lflow_add(lflows, op->od, S_ROUTER_IN_UNSNAT, 110,
-                      ds_cstr(match), "ct_snat;");
+                      ds_cstr(match), "ct_snat;", lflow_ref);
 
         ds_clear(match);
 
@@ -11875,7 +12058,8 @@  build_lrouter_force_snat_flows_op(struct ovn_port *op,
         ds_put_format(actions, "ct_snat(%s);",
                       op->lrp_networks.ipv4_addrs[0].addr_s);
         ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_SNAT, 110,
-                      ds_cstr(match), ds_cstr(actions));
+                      ds_cstr(match), ds_cstr(actions),
+                      lflow_ref);
         if (op->lrp_networks.n_ipv4_addrs > 1) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
             VLOG_WARN_RL(&rl, "Logical router port %s is configured with "
@@ -11895,7 +12079,7 @@  build_lrouter_force_snat_flows_op(struct ovn_port *op,
         ds_put_format(match, "inport == %s && ip6.dst == %s",
                       op->json_key, op->lrp_networks.ipv6_addrs[0].addr_s);
         ovn_lflow_add(lflows, op->od, S_ROUTER_IN_UNSNAT, 110,
-                      ds_cstr(match), "ct_snat;");
+                      ds_cstr(match), "ct_snat;", lflow_ref);
 
         ds_clear(match);
 
@@ -11907,7 +12091,8 @@  build_lrouter_force_snat_flows_op(struct ovn_port *op,
         ds_put_format(actions, "ct_snat(%s);",
                       op->lrp_networks.ipv6_addrs[0].addr_s);
         ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_SNAT, 110,
-                      ds_cstr(match), ds_cstr(actions));
+                      ds_cstr(match), ds_cstr(actions),
+                      lflow_ref);
         if (op->lrp_networks.n_ipv6_addrs > 2) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
             VLOG_WARN_RL(&rl, "Logical router port %s is configured with "
@@ -11921,7 +12106,8 @@  build_lrouter_force_snat_flows_op(struct ovn_port *op,
 
 static void
 build_lrouter_bfd_flows(struct lflow_table *lflows, struct ovn_port *op,
-                        const struct shash *meter_groups)
+                        const struct shash *meter_groups,
+                        struct lflow_ref *lflow_ref)
 {
     if (!op->has_bfd) {
         return;
@@ -11936,7 +12122,8 @@  build_lrouter_bfd_flows(struct lflow_table *lflows, struct ovn_port *op,
                       ds_cstr(&ip_list));
         ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110,
                                 ds_cstr(&match), "next; ",
-                                &op->nbrp->header_);
+                                &op->nbrp->header_,
+                                lflow_ref);
         ds_clear(&match);
         ds_put_format(&match, "ip4.dst == %s && udp.dst == 3784",
                       ds_cstr(&ip_list));
@@ -11944,7 +12131,8 @@  build_lrouter_bfd_flows(struct lflow_table *lflows, struct ovn_port *op,
                                   ds_cstr(&match), "handle_bfd_msg(); ", NULL,
                                   copp_meter_get(COPP_BFD, op->od->nbr->copp,
                                                  meter_groups),
-                                  &op->nbrp->header_);
+                                  &op->nbrp->header_,
+                                  lflow_ref);
     }
     if (op->lrp_networks.n_ipv6_addrs) {
         ds_clear(&ip_list);
@@ -11955,7 +12143,8 @@  build_lrouter_bfd_flows(struct lflow_table *lflows, struct ovn_port *op,
                       ds_cstr(&ip_list));
         ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110,
                                 ds_cstr(&match), "next; ",
-                                &op->nbrp->header_);
+                                &op->nbrp->header_,
+                                lflow_ref);
         ds_clear(&match);
         ds_put_format(&match, "ip6.dst == %s && udp.dst == 3784",
                       ds_cstr(&ip_list));
@@ -11963,7 +12152,8 @@  build_lrouter_bfd_flows(struct lflow_table *lflows, struct ovn_port *op,
                                   ds_cstr(&match), "handle_bfd_msg(); ", NULL,
                                   copp_meter_get(COPP_BFD, op->od->nbr->copp,
                                                  meter_groups),
-                                  &op->nbrp->header_);
+                                  &op->nbrp->header_,
+                                  lflow_ref);
     }
 
     ds_destroy(&ip_list);
@@ -11975,16 +12165,19 @@  build_lrouter_bfd_flows(struct lflow_table *lflows, struct ovn_port *op,
  */
 static void
 build_adm_ctrl_flows_for_lrouter(
-        struct ovn_datapath *od, struct lflow_table *lflows)
+        struct ovn_datapath *od, struct lflow_table *lflows,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
     /* Logical VLANs not supported.
      * Broadcast/multicast source address is invalid. */
     ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 100,
-                  "vlan.present || eth.src[40]", debug_drop_action());
+                  "vlan.present || eth.src[40]", debug_drop_action(),
+                  lflow_ref);
 
     /* Default action for L2 security is to drop. */
-    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ADMISSION);
+    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ADMISSION,
+                               lflow_ref);
 }
 
 static int
@@ -12018,11 +12211,12 @@  build_gateway_get_l2_hdr_size(struct ovn_port *op)
 /* All 'gateway_mtu' and 'gateway_mtu_bypass' flows should be built with this
  * function.
  */
-static void OVS_PRINTF_FORMAT(9, 10)
+static void OVS_PRINTF_FORMAT(10, 11)
 build_gateway_mtu_flow(struct lflow_table *lflows, struct ovn_port *op,
                        enum ovn_stage stage, uint16_t prio_low,
                        uint16_t prio_high, struct ds *match,
                        struct ds *actions, const struct ovsdb_idl_row *hint,
+                       struct lflow_ref *lflow_ref,
                        const char *extra_actions_fmt, ...)
 {
     int gw_mtu = smap_get_int(&op->nbrp->options, "gateway_mtu", 0);
@@ -12040,7 +12234,7 @@  build_gateway_mtu_flow(struct lflow_table *lflows, struct ovn_port *op,
     ds_put_format_valist(actions, extra_actions_fmt, extra_actions_args);
     ovn_lflow_add_with_hint(lflows, op->od, stage, prio_low,
                             ds_cstr(match), ds_cstr(actions),
-                            hint);
+                            hint, lflow_ref);
 
     if (gw_mtu > 0) {
         const char *gw_mtu_bypass = smap_get(&op->nbrp->options,
@@ -12052,7 +12246,7 @@  build_gateway_mtu_flow(struct lflow_table *lflows, struct ovn_port *op,
             ds_put_format(match, " && (%s)", gw_mtu_bypass);
             ovn_lflow_add_with_hint(lflows, op->od, stage, prio_high,
                                     ds_cstr(match), ds_cstr(actions),
-                                    hint);
+                                    hint, lflow_ref);
         }
     }
     va_end(extra_actions_args);
@@ -12081,7 +12275,8 @@  consider_l3dgw_port_is_centralized(struct ovn_port *op)
 static void
 build_adm_ctrl_flows_for_lrouter_port(
         struct ovn_port *op, struct lflow_table *lflows,
-        struct ds *match, struct ds *actions)
+        struct ds *match, struct ds *actions,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbrp);
 
@@ -12105,6 +12300,7 @@  build_adm_ctrl_flows_for_lrouter_port(
     ds_put_format(match, "eth.mcast && inport == %s", op->json_key);
     build_gateway_mtu_flow(lflows, op, S_ROUTER_IN_ADMISSION, 50, 55,
                            match, actions, &op->nbrp->header_,
+                           lflow_ref,
                            REG_INPORT_ETH_ADDR " = %s; next;",
                            op->lrp_networks.ea_s);
 
@@ -12125,6 +12321,7 @@  build_adm_ctrl_flows_for_lrouter_port(
     }
     build_gateway_mtu_flow(lflows, op, S_ROUTER_IN_ADMISSION, 50, 55,
                            match, actions, &op->nbrp->header_,
+                           lflow_ref,
                            REG_INPORT_ETH_ADDR " = %s; next;",
                            op->lrp_networks.ea_s);
 }
@@ -12136,7 +12333,8 @@  static void
 build_neigh_learning_flows_for_lrouter(
         struct ovn_datapath *od, struct lflow_table *lflows,
         struct ds *match, struct ds *actions,
-        const struct shash *meter_groups)
+        const struct shash *meter_groups,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
 
@@ -12183,7 +12381,7 @@  build_neigh_learning_flows_for_lrouter(
                   learn_from_arp_request ? "" :
                   REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; ");
     ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100,
-                  "arp.op == 2", ds_cstr(actions));
+                  "arp.op == 2", ds_cstr(actions), lflow_ref);
 
     ds_clear(actions);
     ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT
@@ -12191,7 +12389,7 @@  build_neigh_learning_flows_for_lrouter(
                   learn_from_arp_request ? "" :
                   REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; ");
     ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_na",
-                  ds_cstr(actions));
+                  ds_cstr(actions), lflow_ref);
 
     if (!learn_from_arp_request) {
         /* Add flow to skip GARP LLA if we don't know it already.
@@ -12208,7 +12406,7 @@  build_neigh_learning_flows_for_lrouter(
                                " = lookup_nd_ip(inport, ip6.src); next;");
         ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 110,
                       "nd_na && ip6.src == fe80::/10 && ip6.dst == ff00::/8",
-                      ds_cstr(actions));
+                      ds_cstr(actions), lflow_ref);
     }
 
     ds_clear(actions);
@@ -12218,12 +12416,13 @@  build_neigh_learning_flows_for_lrouter(
                   REGBIT_LOOKUP_NEIGHBOR_IP_RESULT
                   " = lookup_nd_ip(inport, ip6.src); ");
     ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_ns",
-                  ds_cstr(actions));
+                  ds_cstr(actions), lflow_ref);
 
     /* For other packet types, we can skip neighbor learning.
      * So set REGBIT_LOOKUP_NEIGHBOR_RESULT to 1. */
     ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 0, "1",
-                  REGBIT_LOOKUP_NEIGHBOR_RESULT" = 1; next;");
+                  REGBIT_LOOKUP_NEIGHBOR_RESULT" = 1; next;",
+                  lflow_ref);
 
     /* Flows for LEARN_NEIGHBOR. */
     /* Skip Neighbor learning if not required. */
@@ -12232,33 +12431,40 @@  build_neigh_learning_flows_for_lrouter(
                   learn_from_arp_request ? "" :
                   " || "REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" == 0");
     ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 100,
-                  ds_cstr(match), "mac_cache_use; next;");
+                  ds_cstr(match), "mac_cache_use; next;",
+                  lflow_ref);
 
     ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
                       "arp", "put_arp(inport, arp.spa, arp.sha); next;",
                       copp_meter_get(COPP_ARP, od->nbr->copp,
-                                     meter_groups));
+                                     meter_groups),
+                      lflow_ref);
 
     ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 95,
-                  "nd_ns && (ip6.src == 0 || nd.sll == 0)", "next;");
+                  "nd_ns && (ip6.src == 0 || nd.sll == 0)", "next;",
+                  lflow_ref);
 
     ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 95,
                       "nd_na && nd.tll == 0",
                       "put_nd(inport, nd.target, eth.src); next;",
                       copp_meter_get(COPP_ND_NA, od->nbr->copp,
-                                     meter_groups));
+                                     meter_groups),
+                      lflow_ref);
 
     ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
                       "nd_na", "put_nd(inport, nd.target, nd.tll); next;",
                       copp_meter_get(COPP_ND_NA, od->nbr->copp,
-                                     meter_groups));
+                                     meter_groups),
+                      lflow_ref);
 
     ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
                       "nd_ns", "put_nd(inport, ip6.src, nd.sll); next;",
                       copp_meter_get(COPP_ND_NS, od->nbr->copp,
-                                     meter_groups));
+                                     meter_groups),
+                      lflow_ref);
 
-    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR);
+    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR,
+                               lflow_ref);
 }
 
 /* Logical router ingress Table 1: Neighbor lookup lflows
@@ -12266,7 +12472,8 @@  build_neigh_learning_flows_for_lrouter(
 static void
 build_neigh_learning_flows_for_lrouter_port(
         struct ovn_port *op, struct lflow_table *lflows,
-        struct ds *match, struct ds *actions)
+        struct ds *match, struct ds *actions,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbrp);
 
@@ -12298,7 +12505,8 @@  build_neigh_learning_flows_for_lrouter_port(
             ovn_lflow_add_with_hint(lflows, op->od,
                                     S_ROUTER_IN_LOOKUP_NEIGHBOR, 110,
                                     ds_cstr(match), actions_s,
-                                    &op->nbrp->header_);
+                                    &op->nbrp->header_,
+                                    lflow_ref);
         }
         ds_clear(match);
         ds_put_format(match,
@@ -12319,7 +12527,8 @@  build_neigh_learning_flows_for_lrouter_port(
         ovn_lflow_add_with_hint(lflows, op->od,
                                 S_ROUTER_IN_LOOKUP_NEIGHBOR, 100,
                                 ds_cstr(match), ds_cstr(actions),
-                                &op->nbrp->header_);
+                                &op->nbrp->header_,
+                                lflow_ref);
     }
 }
 
@@ -12329,7 +12538,8 @@  static void
 build_ND_RA_flows_for_lrouter_port(
         struct ovn_port *op, struct lflow_table *lflows,
         struct ds *match, struct ds *actions,
-        const struct shash *meter_groups)
+        const struct shash *meter_groups,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbrp);
     if (op->nbrp->peer || !op->peer) {
@@ -12416,7 +12626,8 @@  build_ND_RA_flows_for_lrouter_port(
                                   copp_meter_get(COPP_ND_RA_OPTS,
                                                  op->od->nbr->copp,
                                                  meter_groups),
-                                  &op->nbrp->header_);
+                                  &op->nbrp->header_,
+                                  lflow_ref);
         ds_clear(actions);
         ds_clear(match);
         ds_put_format(match, "inport == %s && ip6.dst == ff02::2 && "
@@ -12435,7 +12646,8 @@  build_ND_RA_flows_for_lrouter_port(
         ovn_lflow_add_with_hint(lflows, op->od,
                                 S_ROUTER_IN_ND_RA_RESPONSE, 50,
                                 ds_cstr(match), ds_cstr(actions),
-                                &op->nbrp->header_);
+                                &op->nbrp->header_,
+                                lflow_ref);
     }
 }
 
@@ -12443,22 +12655,26 @@  build_ND_RA_flows_for_lrouter_port(
  * responder, by default goto next. (priority 0). */
 static void
 build_ND_RA_flows_for_lrouter(struct ovn_datapath *od,
-                              struct lflow_table *lflows)
+                              struct lflow_table *lflows,
+                              struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
-    ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_OPTIONS, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_RESPONSE, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_OPTIONS, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_RESPONSE, 0, "1", "next;",
+                  lflow_ref);
 }
 
 /* Logical router ingress table IP_ROUTING_PRE:
  * by default goto next. (priority 0). */
 static void
 build_ip_routing_pre_flows_for_lrouter(struct ovn_datapath *od,
-                                       struct lflow_table *lflows)
+                                       struct lflow_table *lflows,
+                                       struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
     ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_PRE, 0, "1",
-                  REG_ROUTE_TABLE_ID" = 0; next;");
+                  REG_ROUTE_TABLE_ID" = 0; next;", lflow_ref);
 }
 
 /* Logical router ingress table IP_ROUTING : IP Routing.
@@ -12482,7 +12698,8 @@  build_ip_routing_pre_flows_for_lrouter(struct ovn_datapath *od,
  */
 static void
 build_ip_routing_flows_for_lrp(
-        struct ovn_port *op, struct lflow_table *lflows)
+        struct ovn_port *op, struct lflow_table *lflows,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbrp);
     for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
@@ -12490,7 +12707,7 @@  build_ip_routing_flows_for_lrp(
                   op->lrp_networks.ipv4_addrs[i].network_s,
                   op->lrp_networks.ipv4_addrs[i].plen, NULL, false, 0,
                   &op->nbrp->header_, false, ROUTE_PRIO_OFFSET_CONNECTED,
-                  NULL);
+                  lflow_ref);
     }
 
     for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
@@ -12498,7 +12715,7 @@  build_ip_routing_flows_for_lrp(
                   op->lrp_networks.ipv6_addrs[i].network_s,
                   op->lrp_networks.ipv6_addrs[i].plen, NULL, false, 0,
                   &op->nbrp->header_, false, ROUTE_PRIO_OFFSET_CONNECTED,
-                  NULL);
+                  lflow_ref);
     }
 }
 
@@ -12563,13 +12780,17 @@  static void
 build_static_route_flows_for_lrouter(
         struct ovn_datapath *od, const struct chassis_features *features,
         struct lflow_table *lflows, const struct hmap *lr_ports,
-        const struct hmap *bfd_connections)
+        const struct hmap *bfd_connections,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
-    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP);
-    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING);
+    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP,
+                               lflow_ref);
+    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING,
+                               lflow_ref);
     ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 150,
-                  REG_ECMP_GROUP_ID" == 0", "next;");
+                  REG_ECMP_GROUP_ID" == 0", "next;",
+                  lflow_ref);
 
     struct hmap ecmp_groups = HMAP_INITIALIZER(&ecmp_groups);
     struct hmap unique_routes = HMAP_INITIALIZER(&unique_routes);
@@ -12579,7 +12800,7 @@  build_static_route_flows_for_lrouter(
 
     for (int i = 0; i < od->nbr->n_ports; i++) {
         build_route_table_lflow(od, lflows, od->nbr->ports[i],
-                                &route_tables);
+                                &route_tables, lflow_ref);
     }
 
     for (int i = 0; i < od->nbr->n_static_routes; i++) {
@@ -12609,11 +12830,11 @@  build_static_route_flows_for_lrouter(
         /* add a flow in IP_ROUTING, and one flow for each member in
          * IP_ROUTING_ECMP. */
         build_ecmp_route_flow(lflows, od, features->ct_no_masked_label,
-                              lr_ports, group);
+                              lr_ports, group, lflow_ref);
     }
     const struct unique_routes_node *ur;
     HMAP_FOR_EACH (ur, hmap_node, &unique_routes) {
-        build_static_route_flow(lflows, od, lr_ports, ur->route);
+        build_static_route_flow(lflows, od, lr_ports, ur->route, lflow_ref);
     }
     ecmp_groups_destroy(&ecmp_groups);
     unique_routes_destroy(&unique_routes);
@@ -12627,7 +12848,8 @@  build_static_route_flows_for_lrouter(
 static void
 build_mcast_lookup_flows_for_lrouter(
         struct ovn_datapath *od, struct lflow_table *lflows,
-        struct ds *match, struct ds *actions)
+        struct ds *match, struct ds *actions,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
 
@@ -12635,7 +12857,8 @@  build_mcast_lookup_flows_for_lrouter(
      * i.e., router solicitation and router advertisement.
      */
     ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550,
-                  "nd_rs || nd_ra", debug_drop_action());
+                  "nd_rs || nd_ra", debug_drop_action(),
+                  lflow_ref);
     if (!od->mcast_info.rtr.relay) {
         return;
     }
@@ -12663,7 +12886,8 @@  build_mcast_lookup_flows_for_lrouter(
         ds_put_format(actions, "outport = \"%s\"; ip.ttl--; next;",
                       igmp_group->mcgroup.name);
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10500,
-                      ds_cstr(match), ds_cstr(actions));
+                      ds_cstr(match), ds_cstr(actions),
+                      lflow_ref);
     }
 
     /* If needed, flood unregistered multicast on statically configured
@@ -12682,13 +12906,15 @@  build_mcast_lookup_flows_for_lrouter(
             ds_put_format(match, "eth.src == %s && igmp",
                           op->lrp_networks.ea_s);
             ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550,
-                          ds_cstr(match), debug_drop_action());
+                          ds_cstr(match), debug_drop_action(),
+                          lflow_ref);
 
             ds_clear(match);
             ds_put_format(match, "eth.src == %s && (mldv1 || mldv2)",
                           op->lrp_networks.ea_s);
             ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550,
-                          ds_cstr(match), debug_drop_action());
+                          ds_cstr(match), debug_drop_action(),
+                          lflow_ref);
         }
 
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10460,
@@ -12696,23 +12922,27 @@  build_mcast_lookup_flows_for_lrouter(
                       "clone { "
                             "outport = \""MC_STATIC"\"; "
                             "next; "
-                      "};");
+                      "};",
+                      lflow_ref);
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10460,
                       "mldv1 || mldv2",
                       "clone { "
                             "outport = \""MC_STATIC"\"; "
                             "next; "
-                      "};");
+                      "};",
+                      lflow_ref);
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10450,
                       "ip4.mcast || ip6.mcast",
                       "clone { "
                             "outport = \""MC_STATIC"\"; "
                             "ip.ttl--; "
                             "next; "
-                      "};");
+                      "};",
+                      lflow_ref);
     } else {
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10450,
-                      "ip4.mcast || ip6.mcast", debug_drop_action());
+                      "ip4.mcast || ip6.mcast", debug_drop_action(),
+                      lflow_ref);
     }
 }
 
@@ -12728,16 +12958,20 @@  build_mcast_lookup_flows_for_lrouter(
 static void
 build_ingress_policy_flows_for_lrouter(
         struct ovn_datapath *od, struct lflow_table *lflows,
-        const struct hmap *lr_ports)
+        const struct hmap *lr_ports,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
     /* This is a catch-all rule. It has the lowest priority (0)
      * does a match-all("1") and pass-through (next) */
     ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY, 0, "1",
-                  REG_ECMP_GROUP_ID" = 0; next;");
+                  REG_ECMP_GROUP_ID" = 0; next;",
+                  lflow_ref);
     ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY_ECMP, 150,
-                  REG_ECMP_GROUP_ID" == 0", "next;");
-    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_POLICY_ECMP);
+                  REG_ECMP_GROUP_ID" == 0", "next;",
+                  lflow_ref);
+    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_POLICY_ECMP,
+                               lflow_ref);
 
     /* Convert routing policies to flows. */
     uint16_t ecmp_group_id = 1;
@@ -12749,11 +12983,11 @@  build_ingress_policy_flows_for_lrouter(
 
         if (is_ecmp_reroute) {
             build_ecmp_routing_policy_flows(lflows, od, lr_ports, rule,
-                                            ecmp_group_id);
+                                            ecmp_group_id, lflow_ref);
             ecmp_group_id++;
         } else {
             build_routing_policy_flow(lflows, od, lr_ports, rule,
-                                      &rule->header_);
+                                      &rule->header_, lflow_ref);
         }
     }
 }
@@ -12761,21 +12995,26 @@  build_ingress_policy_flows_for_lrouter(
 /* Local router ingress table ARP_RESOLVE: ARP Resolution. */
 static void
 build_arp_resolve_flows_for_lrouter(
-        struct ovn_datapath *od, struct lflow_table *lflows)
+        struct ovn_datapath *od, struct lflow_table *lflows,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
     /* Multicast packets already have the outport set so just advance to
      * next table (priority 500). */
     ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 500,
-                  "ip4.mcast || ip6.mcast", "next;");
+                  "ip4.mcast || ip6.mcast", "next;",
+                  lflow_ref);
 
     ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip4",
-                  "get_arp(outport, " REG_NEXT_HOP_IPV4 "); next;");
+                  "get_arp(outport, " REG_NEXT_HOP_IPV4 "); next;",
+                  lflow_ref);
 
     ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip6",
-                  "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;");
+                  "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;",
+                  lflow_ref);
 
-    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ARP_RESOLVE);
+    ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ARP_RESOLVE,
+                               lflow_ref);
 }
 
 static void
@@ -12808,9 +13047,8 @@  routable_addresses_to_lflows(struct lflow_table *lflows,
 
         ds_clear(actions);
         ds_put_format(actions, "eth.dst = %s; next;", ra.laddrs[i].ea_s);
-        ovn_lflow_add_with_lflow_ref(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE,
-                                     100, ds_cstr(match), ds_cstr(actions),
-                                     lflow_ref);
+        ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, 100,
+                      ds_cstr(match), ds_cstr(actions), lflow_ref);
     }
     destroy_routable_addresses(&ra);
 }
@@ -12829,7 +13067,8 @@  routable_addresses_to_lflows(struct lflow_table *lflows,
 static void
 build_arp_resolve_flows_for_lrp(
         struct ovn_port *op,
-        struct lflow_table *lflows, struct ds *match, struct ds *actions)
+        struct lflow_table *lflows, struct ds *match, struct ds *actions,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbrp);
     /* This is a logical router port. If next-hop IP address in
@@ -12854,7 +13093,8 @@  build_arp_resolve_flows_for_lrp(
             ovn_lflow_add_with_hint(lflows, op->peer->od,
                                     S_ROUTER_IN_ARP_RESOLVE, 100,
                                     ds_cstr(match), ds_cstr(actions),
-                                    &op->nbrp->header_);
+                                    &op->nbrp->header_,
+                                    lflow_ref);
         }
 
         if (op->lrp_networks.n_ipv6_addrs) {
@@ -12870,7 +13110,8 @@  build_arp_resolve_flows_for_lrp(
             ovn_lflow_add_with_hint(lflows, op->peer->od,
                                     S_ROUTER_IN_ARP_RESOLVE, 100,
                                     ds_cstr(match), ds_cstr(actions),
-                                    &op->nbrp->header_);
+                                    &op->nbrp->header_,
+                                    lflow_ref);
         }
     }
 
@@ -12895,7 +13136,8 @@  build_arp_resolve_flows_for_lrp(
             ovn_lflow_add_with_hint(lflows, op->od,
                                     S_ROUTER_IN_ARP_RESOLVE, 50,
                                     ds_cstr(match), ds_cstr(actions),
-                                    &op->nbrp->header_);
+                                    &op->nbrp->header_,
+                                    lflow_ref);
         }
     }
 }
@@ -12945,7 +13187,7 @@  build_arp_resolve_flows_for_lsp(
 
                     ds_clear(actions);
                     ds_put_format(actions, "eth.dst = %s; next;", ea_s);
-                    ovn_lflow_add_with_lflow_ref_hint(lflows, peer->od,
+                    ovn_lflow_add_with_hint(lflows, peer->od,
                                             S_ROUTER_IN_ARP_RESOLVE, 100,
                                             ds_cstr(match),
                                             ds_cstr(actions),
@@ -12977,7 +13219,7 @@  build_arp_resolve_flows_for_lsp(
 
                     ds_clear(actions);
                     ds_put_format(actions, "eth.dst = %s; next;", ea_s);
-                    ovn_lflow_add_with_lflow_ref_hint(lflows, peer->od,
+                    ovn_lflow_add_with_hint(lflows, peer->od,
                                             S_ROUTER_IN_ARP_RESOLVE, 100,
                                             ds_cstr(match),
                                             ds_cstr(actions),
@@ -13026,7 +13268,7 @@  build_arp_resolve_flows_for_lsp(
                 ds_clear(actions);
                 ds_put_format(actions, "eth.dst = %s; next;",
                                           router_port->lrp_networks.ea_s);
-                ovn_lflow_add_with_lflow_ref_hint(lflows, peer->od,
+                ovn_lflow_add_with_hint(lflows, peer->od,
                                         S_ROUTER_IN_ARP_RESOLVE, 100,
                                         ds_cstr(match), ds_cstr(actions),
                                         &op->nbsp->header_,
@@ -13043,7 +13285,7 @@  build_arp_resolve_flows_for_lsp(
                 ds_clear(actions);
                 ds_put_format(actions, "eth.dst = %s; next;",
                               router_port->lrp_networks.ea_s);
-                ovn_lflow_add_with_lflow_ref_hint(lflows, peer->od,
+                ovn_lflow_add_with_hint(lflows, peer->od,
                                         S_ROUTER_IN_ARP_RESOLVE, 100,
                                         ds_cstr(match), ds_cstr(actions),
                                         &op->nbsp->header_,
@@ -13104,7 +13346,8 @@  build_icmperr_pkt_big_flows(struct ovn_port *op, int mtu,
                             struct lflow_table *lflows,
                             const struct shash *meter_groups, struct ds *match,
                             struct ds *actions, enum ovn_stage stage,
-                            struct ovn_port *outport)
+                            struct ovn_port *outport,
+                            struct lflow_ref *lflow_ref)
 {
     char *outport_match = outport ? xasprintf("outport == %s && ",
                                               outport->json_key)
@@ -13147,7 +13390,8 @@  build_icmperr_pkt_big_flows(struct ovn_port *op, int mtu,
                                         COPP_ICMP4_ERR,
                                         op->od->nbr->copp,
                                         meter_groups),
-                                  &op->nbrp->header_);
+                                  &op->nbrp->header_,
+                                  lflow_ref);
     }
 
     char *ip6_src = NULL;
@@ -13187,7 +13431,8 @@  build_icmperr_pkt_big_flows(struct ovn_port *op, int mtu,
                                         COPP_ICMP6_ERR,
                                         op->od->nbr->copp,
                                         meter_groups),
-                                  &op->nbrp->header_);
+                                  &op->nbrp->header_,
+                                  lflow_ref);
     }
     free(outport_match);
 }
@@ -13198,7 +13443,8 @@  build_check_pkt_len_flows_for_lrp(struct ovn_port *op,
                                   const struct hmap *lr_ports,
                                   const struct shash *meter_groups,
                                   struct ds *match,
-                                  struct ds *actions)
+                                  struct ds *actions,
+                                  struct lflow_ref *lflow_ref)
 {
     int gw_mtu = smap_get_int(&op->nbrp->options, "gateway_mtu", 0);
     if (gw_mtu <= 0) {
@@ -13208,12 +13454,13 @@  build_check_pkt_len_flows_for_lrp(struct ovn_port *op,
     ds_clear(match);
     ds_put_format(match, "outport == %s", op->json_key);
     build_gateway_mtu_flow(lflows, op, S_ROUTER_IN_CHK_PKT_LEN, 50, 55,
-                           match, actions, &op->nbrp->header_, "next;");
+                           match, actions, &op->nbrp->header_,
+                           lflow_ref, "next;");
 
     /* ingress traffic */
     build_icmperr_pkt_big_flows(op, gw_mtu, lflows, meter_groups,
                                 match, actions, S_ROUTER_IN_IP_INPUT,
-                                NULL);
+                                NULL, lflow_ref);
 
     for (size_t i = 0; i < op->od->nbr->n_ports; i++) {
         struct ovn_port *rp = ovn_port_find(lr_ports,
@@ -13225,7 +13472,7 @@  build_check_pkt_len_flows_for_lrp(struct ovn_port *op,
         /* egress traffic */
         build_icmperr_pkt_big_flows(rp, gw_mtu, lflows, meter_groups,
                                     match, actions, S_ROUTER_IN_LARGER_PKTS,
-                                    op);
+                                    op, lflow_ref);
     }
 }
 
@@ -13247,15 +13494,16 @@  build_check_pkt_len_flows_for_lrouter(
         struct ovn_datapath *od, struct lflow_table *lflows,
         const struct hmap *lr_ports,
         struct ds *match, struct ds *actions,
-        const struct shash *meter_groups)
+        const struct shash *meter_groups,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
 
     /* Packets are allowed by default. */
     ovn_lflow_add(lflows, od, S_ROUTER_IN_CHK_PKT_LEN, 0, "1",
-                  "next;");
+                  "next;", lflow_ref);
     ovn_lflow_add(lflows, od, S_ROUTER_IN_LARGER_PKTS, 0, "1",
-                  "next;");
+                  "next;", lflow_ref);
 
     for (size_t i = 0; i < od->nbr->n_ports; i++) {
         struct ovn_port *rp = ovn_port_find(lr_ports,
@@ -13264,7 +13512,7 @@  build_check_pkt_len_flows_for_lrouter(
             continue;
         }
         build_check_pkt_len_flows_for_lrp(rp, lflows, lr_ports, meter_groups,
-                                          match, actions);
+                                          match, actions, lflow_ref);
     }
 }
 
@@ -13272,7 +13520,8 @@  build_check_pkt_len_flows_for_lrouter(
 static void
 build_gateway_redirect_flows_for_lrouter(
         struct ovn_datapath *od, struct lflow_table *lflows,
-        struct ds *match, struct ds *actions)
+        struct ds *match, struct ds *actions,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
     for (size_t i = 0; i < od->n_l3dgw_ports; i++) {
@@ -13305,18 +13554,20 @@  build_gateway_redirect_flows_for_lrouter(
                       od->l3dgw_ports[i]->cr_port->json_key);
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50,
                                 ds_cstr(match), ds_cstr(actions),
-                                stage_hint);
+                                stage_hint, lflow_ref);
     }
 
     /* Packets are allowed by default. */
-    ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 0, "1", "next;",
+                  lflow_ref);
 }
 
 /* Logical router ingress table GW_REDIRECT: Gateway redirect. */
 static void
 build_lr_gateway_redirect_flows_for_nats(
         const struct ovn_datapath *od, const struct lr_nat_record *lrnat_rec,
-        struct lflow_table *lflows, struct ds *match, struct ds *actions)
+        struct lflow_table *lflows, struct ds *match, struct ds *actions,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
     for (size_t i = 0; i < od->n_l3dgw_ports; i++) {
@@ -13357,21 +13608,23 @@  build_lr_gateway_redirect_flows_for_nats(
             if (nat->nb->allowed_ext_ips) {
                 ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT,
                                         75, ds_cstr(&match_ext),
-                                        ds_cstr(actions), stage_hint);
+                                        ds_cstr(actions), stage_hint,
+                                        lflow_ref);
                 if (add_def_flow) {
                     ds_clear(&match_ext);
                     ds_put_format(&match_ext, "ip && ip%s.dst == %s",
                                   nat_entry_is_v6(nat) ? "6" : "4",
                                   nat->nb->external_ip);
                     ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 70,
-                                  ds_cstr(&match_ext), debug_drop_action());
+                                  ds_cstr(&match_ext), debug_drop_action(),
+                                  lflow_ref);
                     add_def_flow = false;
                 }
             } else if (nat->nb->exempted_ext_ips) {
                 ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT,
                                         75, ds_cstr(&match_ext),
                                         debug_drop_action(),
-                                        stage_hint);
+                                        stage_hint, lflow_ref);
             }
             ds_destroy(&match_ext);
         }
@@ -13387,7 +13640,8 @@  static void
 build_arp_request_flows_for_lrouter(
         struct ovn_datapath *od, struct lflow_table *lflows,
         struct ds *match, struct ds *actions,
-        const struct shash *meter_groups)
+        const struct shash *meter_groups,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
     for (int i = 0; i < od->nbr->n_static_routes; i++) {
@@ -13429,7 +13683,8 @@  build_arp_request_flows_for_lrouter(
                                   copp_meter_get(COPP_ND_NS_RESOLVE,
                                                  od->nbr->copp,
                                                  meter_groups),
-                                  &route->header_);
+                                  &route->header_,
+                                  lflow_ref);
     }
 
     ovn_lflow_metered(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100,
@@ -13442,7 +13697,8 @@  build_arp_request_flows_for_lrouter(
                       "output; "
                       "};",
                       copp_meter_get(COPP_ARP_RESOLVE, od->nbr->copp,
-                                     meter_groups));
+                                     meter_groups),
+                      lflow_ref);
     ovn_lflow_metered(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100,
                       "eth.dst == 00:00:00:00:00:00 && ip6",
                       "nd_ns { "
@@ -13450,8 +13706,10 @@  build_arp_request_flows_for_lrouter(
                       "output; "
                       "};",
                       copp_meter_get(COPP_ND_NS_RESOLVE, od->nbr->copp,
-                                     meter_groups));
-    ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1", "output;");
+                                     meter_groups),
+                      lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1", "output;",
+                  lflow_ref);
 }
 
 /* Logical router egress table DELIVERY: Delivery (priority 100-110).
@@ -13464,7 +13722,8 @@  build_arp_request_flows_for_lrouter(
 static void
 build_egress_delivery_flows_for_lrouter_port(
         struct ovn_port *op, struct lflow_table *lflows,
-        struct ds *match, struct ds *actions)
+        struct ds *match, struct ds *actions,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbrp);
     if (!lrport_is_enabled(op->nbrp)) {
@@ -13492,20 +13751,23 @@  build_egress_delivery_flows_for_lrouter_port(
         ds_put_format(actions, "eth.src = %s; output;",
                       op->lrp_networks.ea_s);
         ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 110,
-                      ds_cstr(match), ds_cstr(actions));
+                      ds_cstr(match), ds_cstr(actions),
+                      lflow_ref);
     }
 
     ds_clear(match);
     ds_put_format(match, "outport == %s", op->json_key);
     ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 100,
-                  ds_cstr(match), "output;");
+                  ds_cstr(match), "output;", lflow_ref);
 
-    ovn_lflow_add_default_drop(lflows, op->od, S_ROUTER_OUT_DELIVERY);
+    ovn_lflow_add_default_drop(lflows, op->od, S_ROUTER_OUT_DELIVERY,
+                               lflow_ref);
 }
 
 static void
 build_misc_local_traffic_drop_flows_for_lrouter(
-        struct ovn_datapath *od, struct lflow_table *lflows)
+        struct ovn_datapath *od, struct lflow_table *lflows,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
     /* Allow IGMP and MLD packets (with TTL = 1) if the router is
@@ -13513,9 +13775,11 @@  build_misc_local_traffic_drop_flows_for_lrouter(
      */
     if (od->mcast_info.rtr.flood_static) {
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 120,
-                      "igmp && ip.ttl == 1", "next;");
+                      "igmp && ip.ttl == 1", "next;",
+                      lflow_ref);
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 120,
-                      "(mldv1 || mldv2) && ip.ttl == 1", "next;");
+                      "(mldv1 || mldv2) && ip.ttl == 1", "next;",
+                      lflow_ref);
     }
 
     /* L3 admission control: drop multicast and broadcast source, localhost
@@ -13528,7 +13792,8 @@  build_misc_local_traffic_drop_flows_for_lrouter(
                   "ip4.dst == 127.0.0.0/8 || "
                   "ip4.src == 0.0.0.0/8 || "
                   "ip4.dst == 0.0.0.0/8",
-                  debug_drop_action());
+                  debug_drop_action(),
+                  lflow_ref);
 
     /* Drop ARP packets (priority 85). ARP request packets for router's own
      * IPs are handled with priority-90 flows.
@@ -13536,28 +13801,32 @@  build_misc_local_traffic_drop_flows_for_lrouter(
      * IPs are handled with priority-90 flows.
      */
     ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 85,
-                  "arp || nd", debug_drop_action());
+                  "arp || nd", debug_drop_action(),
+                  lflow_ref);
 
     /* Allow IPv6 multicast traffic that's supposed to reach the
      * router pipeline (e.g., router solicitations).
      */
     ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 84, "nd_rs || nd_ra",
-                  "next;");
+                  "next;", lflow_ref);
 
     /* Drop other reserved multicast. */
     ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 83,
-                  "ip6.mcast_rsvd", debug_drop_action());
+                  "ip6.mcast_rsvd", debug_drop_action(),
+                  lflow_ref);
 
     /* Allow other multicast if relay enabled (priority 82). */
     ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 82,
                   "ip4.mcast || ip6.mcast",
                   (od->mcast_info.rtr.relay ? "next;" :
-                                              debug_drop_action()));
+                                              debug_drop_action()),
+                  lflow_ref);
 
     /* Drop Ethernet local broadcast.  By definition this traffic should
      * not be forwarded.*/
     ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50,
-                  "eth.bcast", debug_drop_action());
+                  "eth.bcast", debug_drop_action(),
+                  lflow_ref);
 
     /* Avoid ICMP time exceeded for multicast, silent drop instead.
      * See RFC1812 section 5.3.1:
@@ -13574,21 +13843,25 @@  build_misc_local_traffic_drop_flows_for_lrouter(
      * (priority-31 flows will send ICMP time exceeded) */
     ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 32,
                   "ip.ttl == {0, 1} && !ip.later_frag && "
-                  "(ip4.mcast || ip6.mcast)", debug_drop_action());
+                  "(ip4.mcast || ip6.mcast)", debug_drop_action(),
+                  lflow_ref);
 
     /* TTL discard */
     ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30,
-                  "ip.ttl == {0, 1}", debug_drop_action());
+                  "ip.ttl == {0, 1}", debug_drop_action(),
+                  lflow_ref);
 
     /* Pass other traffic not already handled to the next table for
      * routing. */
-    ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 0, "1", "next;",
+                  lflow_ref);
 }
 
 static void
 build_dhcpv6_reply_flows_for_lrouter_port(
         struct ovn_port *op, struct lflow_table *lflows,
-        struct ds *match)
+        struct ds *match,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbrp);
     if (op->l3dgw_port) {
@@ -13601,7 +13874,8 @@  build_dhcpv6_reply_flows_for_lrouter_port(
                       op->lrp_networks.ipv6_addrs[i].addr_s);
         ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
                       ds_cstr(match),
-                      "reg0 = 0; handle_dhcpv6_reply;");
+                      "reg0 = 0; handle_dhcpv6_reply;",
+                      lflow_ref);
     }
 }
 
@@ -13609,7 +13883,8 @@  static void
 build_ipv6_input_flows_for_lrouter_port(
         struct ovn_port *op, struct lflow_table *lflows,
         struct ds *match, struct ds *actions,
-        const struct shash *meter_groups)
+        const struct shash *meter_groups,
+        struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbrp);
     if (is_cr_port(op)) {
@@ -13633,7 +13908,7 @@  build_ipv6_input_flows_for_lrouter_port(
                     "next; ";
         ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
                                 ds_cstr(match), lrp_actions,
-                                &op->nbrp->header_);
+                                &op->nbrp->header_, lflow_ref);
     }
 
     /* ND reply.  These flows reply to ND solicitations for the
@@ -13654,7 +13929,8 @@  build_ipv6_input_flows_for_lrouter_port(
                               op->lrp_networks.ipv6_addrs[i].addr_s,
                               op->lrp_networks.ipv6_addrs[i].sn_addr_s,
                               REG_INPORT_ETH_ADDR, match, false, 90,
-                              &op->nbrp->header_, lflows, meter_groups);
+                              &op->nbrp->header_, lflows, meter_groups,
+                              lflow_ref);
     }
 
     /* UDP/TCP/SCTP port unreachable */
@@ -13674,7 +13950,8 @@  build_ipv6_input_flows_for_lrouter_port(
                                           COPP_TCP_RESET,
                                           op->od->nbr->copp,
                                           meter_groups),
-                                      &op->nbrp->header_);
+                                      &op->nbrp->header_,
+                                      lflow_ref);
 
             ds_clear(match);
             ds_put_format(match,
@@ -13690,7 +13967,8 @@  build_ipv6_input_flows_for_lrouter_port(
                                           COPP_TCP_RESET,
                                           op->od->nbr->copp,
                                           meter_groups),
-                                      &op->nbrp->header_);
+                                      &op->nbrp->header_,
+                                      lflow_ref);
 
             ds_clear(match);
             ds_put_format(match,
@@ -13709,7 +13987,8 @@  build_ipv6_input_flows_for_lrouter_port(
                                           COPP_ICMP6_ERR,
                                           op->od->nbr->copp,
                                           meter_groups),
-                                      &op->nbrp->header_);
+                                      &op->nbrp->header_,
+                                      lflow_ref);
 
             ds_clear(match);
             ds_put_format(match,
@@ -13728,7 +14007,8 @@  build_ipv6_input_flows_for_lrouter_port(
                                           COPP_ICMP6_ERR,
                                           op->od->nbr->copp,
                                           meter_groups),
-                                      &op->nbrp->header_);
+                                      &op->nbrp->header_,
+                                      lflow_ref);
         }
     }
 
@@ -13768,7 +14048,7 @@  build_ipv6_input_flows_for_lrouter_port(
                 31, ds_cstr(match), ds_cstr(actions), NULL,
                 copp_meter_get(COPP_ICMP6_ERR, op->od->nbr->copp,
                                meter_groups),
-                &op->nbrp->header_);
+                &op->nbrp->header_, lflow_ref);
     }
     ds_destroy(&ip_ds);
 }
@@ -13777,7 +14057,8 @@  static void
 build_lrouter_arp_nd_for_datapath(const struct ovn_datapath *od,
                                   const struct lr_nat_record *lrnat_rec,
                                   struct lflow_table *lflows,
-                                  const struct shash *meter_groups)
+                                  const struct shash *meter_groups,
+                                  struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
     if (!od->nbr->n_nat) {
@@ -13806,7 +14087,8 @@  build_lrouter_arp_nd_for_datapath(const struct ovn_datapath *od,
         if (!strcmp(nat_entry->nb->type, "snat")) {
             continue;
         }
-        build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows, meter_groups);
+        build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows, meter_groups,
+                                      lflow_ref);
     }
 
     /* Now handle SNAT entries too, one per unique SNAT IP. */
@@ -13821,7 +14103,8 @@  build_lrouter_arp_nd_for_datapath(const struct ovn_datapath *od,
         struct ovn_nat *nat_entry =
             CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries),
                          struct ovn_nat, ext_addr_list_node);
-        build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows, meter_groups);
+        build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows, meter_groups,
+                                      lflow_ref);
     }
 }
 
@@ -13830,7 +14113,8 @@  static void
 build_lrouter_ipv4_ip_input(struct ovn_port *op,
                             struct lflow_table *lflows,
                             struct ds *match, struct ds *actions,
-                            const struct shash *meter_groups)
+                            const struct shash *meter_groups,
+                            struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbrp);
     /* No ingress packets are accepted on a chassisredirect
@@ -13848,7 +14132,7 @@  build_lrouter_ipv4_ip_input(struct ovn_port *op,
         ds_put_cstr(match, " && "REGBIT_EGRESS_LOOPBACK" == 0");
         ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
                                 ds_cstr(match), debug_drop_action(),
-                                &op->nbrp->header_);
+                                &op->nbrp->header_, lflow_ref);
 
         /* ICMP echo reply.  These flows reply to ICMP echo requests
          * received for the router's IP address. Since packets only
@@ -13867,11 +14151,11 @@  build_lrouter_ipv4_ip_input(struct ovn_port *op,
                       "next; ";
         ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
                                 ds_cstr(match), icmp_actions,
-                                &op->nbrp->header_);
+                                &op->nbrp->header_, lflow_ref);
     }
 
     /* BFD msg handling */
-    build_lrouter_bfd_flows(lflows, op, meter_groups);
+    build_lrouter_bfd_flows(lflows, op, meter_groups, lflow_ref);
 
     /* ICMP time exceeded */
     struct ds ip_ds = DS_EMPTY_INITIALIZER;
@@ -13900,7 +14184,7 @@  build_lrouter_ipv4_ip_input(struct ovn_port *op,
                 31, ds_cstr(match), ds_cstr(actions), NULL,
                 copp_meter_get(COPP_ICMP4_ERR, op->od->nbr->copp,
                                meter_groups),
-                &op->nbrp->header_);
+                &op->nbrp->header_, lflow_ref);
 
     }
     ds_destroy(&ip_ds);
@@ -13950,7 +14234,7 @@  build_lrouter_ipv4_ip_input(struct ovn_port *op,
         build_lrouter_arp_flow(op->od, op,
                                op->lrp_networks.ipv4_addrs[i].addr_s,
                                REG_INPORT_ETH_ADDR, match, false, 90,
-                               &op->nbrp->header_, lflows);
+                               &op->nbrp->header_, lflows, lflow_ref);
     }
 
     if (!op->od->is_gw_router && !op->od->n_l3dgw_ports) {
@@ -13973,7 +14257,8 @@  build_lrouter_ipv4_ip_input(struct ovn_port *op,
                                           COPP_ICMP4_ERR,
                                           op->od->nbr->copp,
                                           meter_groups),
-                                      &op->nbrp->header_);
+                                      &op->nbrp->header_,
+                                      lflow_ref);
 
             ds_clear(match);
             ds_put_format(match,
@@ -13989,7 +14274,8 @@  build_lrouter_ipv4_ip_input(struct ovn_port *op,
                                           COPP_TCP_RESET,
                                           op->od->nbr->copp,
                                           meter_groups),
-                                      &op->nbrp->header_);
+                                      &op->nbrp->header_,
+                                      lflow_ref);
 
             ds_clear(match);
             ds_put_format(match,
@@ -14005,7 +14291,8 @@  build_lrouter_ipv4_ip_input(struct ovn_port *op,
                                           COPP_TCP_RESET,
                                           op->od->nbr->copp,
                                           meter_groups),
-                                      &op->nbrp->header_);
+                                      &op->nbrp->header_,
+                                      lflow_ref);
 
             ds_clear(match);
             ds_put_format(match,
@@ -14024,7 +14311,8 @@  build_lrouter_ipv4_ip_input(struct ovn_port *op,
                                           COPP_ICMP4_ERR,
                                           op->od->nbr->copp,
                                           meter_groups),
-                                      &op->nbrp->header_);
+                                      &op->nbrp->header_,
+                                      lflow_ref);
         }
     }
 }
@@ -14034,7 +14322,8 @@  static void
 build_lrouter_ipv4_ip_input_for_lbnats(struct ovn_port *op,
                             struct lflow_table *lflows,
                             const struct lr_stateful_record *lr_sful_rec,
-                            struct ds *match, const struct shash *meter_groups)
+                            struct ds *match, const struct shash *meter_groups,
+                            struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbrp);
     /* No ingress packets are accepted on a chassisredirect
@@ -14055,7 +14344,7 @@  build_lrouter_ipv4_ip_input_for_lbnats(struct ovn_port *op,
                                                    AF_INET);
         build_lrouter_arp_flow(op->od, op, lb_ips_v4_as,
                                REG_INPORT_ETH_ADDR,
-                               match, false, 90, NULL, lflows);
+                               match, false, 90, NULL, lflows, lflow_ref);
         free(lb_ips_v4_as);
     }
 
@@ -14072,7 +14361,7 @@  build_lrouter_ipv4_ip_input_for_lbnats(struct ovn_port *op,
                                                    AF_INET6);
         build_lrouter_nd_flow(op->od, op, "nd_na", lb_ips_v6_as, NULL,
                               REG_INPORT_ETH_ADDR, match, false, 90,
-                              NULL, lflows, meter_groups);
+                              NULL, lflows, meter_groups, lflow_ref);
         free(lb_ips_v6_as);
     }
 
@@ -14104,7 +14393,7 @@  build_lrouter_ipv4_ip_input_for_lbnats(struct ovn_port *op,
             continue;
         }
         build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows,
-                                        meter_groups);
+                                        meter_groups, lflow_ref);
     }
 
     /* Now handle SNAT entries too, one per unique SNAT IP. */
@@ -14120,7 +14409,7 @@  build_lrouter_ipv4_ip_input_for_lbnats(struct ovn_port *op,
             CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries),
                         struct ovn_nat, ext_addr_list_node);
         build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows,
-                                        meter_groups);
+                                        meter_groups, lflow_ref);
     }
 }
 
@@ -14156,7 +14445,8 @@  build_lrouter_in_unsnat_stateless_flow(struct lflow_table *lflows,
                                        const struct nbrec_nat *nat,
                                        struct ds *match,
                                        bool distributed_nat, bool is_v6,
-                                       struct ovn_port *l3dgw_port)
+                                       struct ovn_port *l3dgw_port,
+                                       struct lflow_ref *lflow_ref)
 {
     if (strcmp(nat->type, "snat") && strcmp(nat->type, "dnat_and_snat")) {
         return;
@@ -14169,7 +14459,7 @@  build_lrouter_in_unsnat_stateless_flow(struct lflow_table *lflows,
 
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT,
                             priority, ds_cstr(match), "next;",
-                            &nat->header_);
+                            &nat->header_, lflow_ref);
 }
 
 static void
@@ -14177,7 +14467,8 @@  build_lrouter_in_unsnat_in_czone_flow(struct lflow_table *lflows,
                                       const struct ovn_datapath *od,
                                       const struct nbrec_nat *nat,
                                       struct ds *match, bool distributed_nat,
-                                      bool is_v6, struct ovn_port *l3dgw_port)
+                                      bool is_v6, struct ovn_port *l3dgw_port,
+                                      struct lflow_ref *lflow_ref)
 {
     if (strcmp(nat->type, "snat") && strcmp(nat->type, "dnat_and_snat")) {
         return;
@@ -14195,7 +14486,7 @@  build_lrouter_in_unsnat_in_czone_flow(struct lflow_table *lflows,
     ds_put_cstr(match, " && flags.loopback == 0");
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT,
                             100, ds_cstr(match), "ct_snat_in_czone;",
-                            &nat->header_);
+                            &nat->header_, lflow_ref);
 
     ds_truncate(match, common_match_len);
     /* Update common zone match for the hairpin traffic. */
@@ -14203,7 +14494,7 @@  build_lrouter_in_unsnat_in_czone_flow(struct lflow_table *lflows,
 
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT,
                             100, ds_cstr(match), "ct_snat;",
-                            &nat->header_);
+                            &nat->header_, lflow_ref);
 }
 
 static void
@@ -14211,7 +14502,8 @@  build_lrouter_in_unsnat_flow(struct lflow_table *lflows,
                              const struct ovn_datapath *od,
                              const struct nbrec_nat *nat, struct ds *match,
                              bool distributed_nat, bool is_v6,
-                             struct ovn_port *l3dgw_port)
+                             struct ovn_port *l3dgw_port,
+                             struct lflow_ref *lflow_ref)
 {
 
     if (strcmp(nat->type, "snat") && strcmp(nat->type, "dnat_and_snat")) {
@@ -14225,7 +14517,7 @@  build_lrouter_in_unsnat_flow(struct lflow_table *lflows,
 
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT,
                             priority, ds_cstr(match), "ct_snat;",
-                            &nat->header_);
+                            &nat->header_, lflow_ref);
 }
 
 static void
@@ -14235,7 +14527,8 @@  build_lrouter_in_dnat_flow(struct lflow_table *lflows,
                            const struct nbrec_nat *nat, struct ds *match,
                            struct ds *actions, bool distributed_nat,
                            int cidr_bits, bool is_v6,
-                           struct ovn_port *l3dgw_port, bool stateless)
+                           struct ovn_port *l3dgw_port, bool stateless,
+                           struct lflow_ref *lflow_ref)
 {
     /* Ingress DNAT table: Packets enter the pipeline with destination
     * IP address that needs to be DNATted from a external IP address
@@ -14281,7 +14574,8 @@  build_lrouter_in_dnat_flow(struct lflow_table *lflows,
 
     if (nat->allowed_ext_ips || nat->exempted_ext_ips) {
         lrouter_nat_add_ext_ip_match(od, lflows, match, nat,
-                                     is_v6, true, cidr_bits);
+                                     is_v6, true, cidr_bits,
+                                     lflow_ref);
     }
 
     if (stateless) {
@@ -14297,7 +14591,7 @@  build_lrouter_in_dnat_flow(struct lflow_table *lflows,
 
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, 100,
                             ds_cstr(match), ds_cstr(actions),
-                            &nat->header_);
+                            &nat->header_, lflow_ref);
 }
 
 static void
@@ -14306,7 +14600,8 @@  build_lrouter_out_undnat_flow(struct lflow_table *lflows,
                               const struct nbrec_nat *nat, struct ds *match,
                               struct ds *actions, bool distributed_nat,
                               struct eth_addr mac, bool is_v6,
-                              struct ovn_port *l3dgw_port, bool stateless)
+                              struct ovn_port *l3dgw_port, bool stateless,
+                              struct lflow_ref *lflow_ref)
 {
     /* Egress UNDNAT table: It is for already established connections'
     * reverse traffic. i.e., DNAT has already been done in ingress
@@ -14348,7 +14643,7 @@  build_lrouter_out_undnat_flow(struct lflow_table *lflows,
 
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 100,
                             ds_cstr(match), ds_cstr(actions),
-                            &nat->header_);
+                            &nat->header_, lflow_ref);
 }
 
 static void
@@ -14356,7 +14651,8 @@  build_lrouter_out_is_dnat_local(struct lflow_table *lflows,
                                 const struct ovn_datapath *od,
                                 const struct nbrec_nat *nat, struct ds *match,
                                 struct ds *actions, bool distributed_nat,
-                                bool is_v6, struct ovn_port *l3dgw_port)
+                                bool is_v6, struct ovn_port *l3dgw_port,
+                                struct lflow_ref *lflow_ref)
 {
     /* Note that this only applies for NAT on a distributed router.
      */
@@ -14379,7 +14675,7 @@  build_lrouter_out_is_dnat_local(struct lflow_table *lflows,
 
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_CHECK_DNAT_LOCAL,
                             50, ds_cstr(match), ds_cstr(actions),
-                            &nat->header_);
+                            &nat->header_, lflow_ref);
 }
 
 static void
@@ -14387,7 +14683,8 @@  build_lrouter_out_snat_match(struct lflow_table *lflows,
                              const struct ovn_datapath *od,
                              const struct nbrec_nat *nat, struct ds *match,
                              bool distributed_nat, int cidr_bits, bool is_v6,
-                             struct ovn_port *l3dgw_port)
+                             struct ovn_port *l3dgw_port,
+                             struct lflow_ref *lflow_ref)
 {
     ds_clear(match);
 
@@ -14407,7 +14704,8 @@  build_lrouter_out_snat_match(struct lflow_table *lflows,
 
     if (nat->allowed_ext_ips || nat->exempted_ext_ips) {
         lrouter_nat_add_ext_ip_match(od, lflows, match, nat,
-                                     is_v6, false, cidr_bits);
+                                     is_v6, false, cidr_bits,
+                                     lflow_ref);
     }
 }
 
@@ -14418,7 +14716,8 @@  build_lrouter_out_snat_stateless_flow(struct lflow_table *lflows,
                                       struct ds *match, struct ds *actions,
                                       bool distributed_nat,
                                       struct eth_addr mac, int cidr_bits,
-                                      bool is_v6, struct ovn_port *l3dgw_port)
+                                      bool is_v6, struct ovn_port *l3dgw_port,
+                                      struct lflow_ref *lflow_ref)
 {
     if (strcmp(nat->type, "snat") && strcmp(nat->type, "dnat_and_snat")) {
         return;
@@ -14432,7 +14731,7 @@  build_lrouter_out_snat_stateless_flow(struct lflow_table *lflows,
     uint16_t priority = cidr_bits + 1;
 
     build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat,
-                                 cidr_bits, is_v6, l3dgw_port);
+                                 cidr_bits, is_v6, l3dgw_port, lflow_ref);
 
     if (!od->is_gw_router) {
         /* Distributed router. */
@@ -14451,7 +14750,8 @@  build_lrouter_out_snat_stateless_flow(struct lflow_table *lflows,
 
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_SNAT,
                             priority, ds_cstr(match),
-                            ds_cstr(actions), &nat->header_);
+                            ds_cstr(actions), &nat->header_,
+                            lflow_ref);
 }
 
 static void
@@ -14461,7 +14761,8 @@  build_lrouter_out_snat_in_czone_flow(struct lflow_table *lflows,
                                      struct ds *match,
                                      struct ds *actions, bool distributed_nat,
                                      struct eth_addr mac, int cidr_bits,
-                                     bool is_v6, struct ovn_port *l3dgw_port)
+                                     bool is_v6, struct ovn_port *l3dgw_port,
+                                     struct lflow_ref *lflow_ref)
 {
     if (strcmp(nat->type, "snat") && strcmp(nat->type, "dnat_and_snat")) {
         return;
@@ -14476,7 +14777,8 @@  build_lrouter_out_snat_in_czone_flow(struct lflow_table *lflows,
     struct ds zone_actions = DS_EMPTY_INITIALIZER;
 
     build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat,
-                                 cidr_bits, is_v6, l3dgw_port);
+                                 cidr_bits, is_v6, l3dgw_port,
+                                 lflow_ref);
 
     if (od->n_l3dgw_ports) {
         priority += 128;
@@ -14505,13 +14807,15 @@  build_lrouter_out_snat_in_czone_flow(struct lflow_table *lflows,
 
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_SNAT,
                             priority, ds_cstr(match),
-                            ds_cstr(actions), &nat->header_);
+                            ds_cstr(actions), &nat->header_,
+                            lflow_ref);
 
     ds_put_cstr(match, " && "REGBIT_DST_NAT_IP_LOCAL" == 1");
 
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_SNAT,
                             priority + 1, ds_cstr(match),
-                            ds_cstr(&zone_actions), &nat->header_);
+                            ds_cstr(&zone_actions), &nat->header_,
+                            lflow_ref);
 
     ds_destroy(&zone_actions);
 }
@@ -14522,7 +14826,8 @@  build_lrouter_out_snat_flow(struct lflow_table *lflows,
                             const struct nbrec_nat *nat, struct ds *match,
                             struct ds *actions, bool distributed_nat,
                             struct eth_addr mac, int cidr_bits, bool is_v6,
-                            struct ovn_port *l3dgw_port)
+                            struct ovn_port *l3dgw_port,
+                            struct lflow_ref *lflow_ref)
 {
     if (strcmp(nat->type, "snat") && strcmp(nat->type, "dnat_and_snat")) {
         return;
@@ -14536,7 +14841,7 @@  build_lrouter_out_snat_flow(struct lflow_table *lflows,
     uint16_t priority = cidr_bits + 1;
 
     build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat,
-                                 cidr_bits, is_v6, l3dgw_port);
+                                 cidr_bits, is_v6, l3dgw_port, lflow_ref);
 
     if (!od->is_gw_router) {
         /* Distributed router. */
@@ -14559,7 +14864,8 @@  build_lrouter_out_snat_flow(struct lflow_table *lflows,
 
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_SNAT,
                             priority, ds_cstr(match),
-                            ds_cstr(actions), &nat->header_);
+                            ds_cstr(actions), &nat->header_,
+                            lflow_ref);
 }
 
 static void
@@ -14569,7 +14875,8 @@  build_lrouter_ingress_nat_check_pkt_len(struct lflow_table *lflows,
                                         bool is_v6, struct ds *match,
                                         struct ds *actions, int mtu,
                                         struct ovn_port *l3dgw_port,
-                                        const struct shash *meter_groups)
+                                        const struct shash *meter_groups,
+                                        struct lflow_ref *lflow_ref)
 {
         ds_clear(match);
         ds_put_format(match, "inport == %s && "REGBIT_PKT_LARGER
@@ -14603,7 +14910,8 @@  build_lrouter_ingress_nat_check_pkt_len(struct lflow_table *lflows,
                                             COPP_ICMP4_ERR,
                                             od->nbr->copp,
                                             meter_groups),
-                                      &nat->header_);
+                                      &nat->header_,
+                                      lflow_ref);
         } else {
             ds_put_format(match, " && ip6 && ip6.dst == %s", nat->external_ip);
             /* Set icmp6.frag_mtu to gw_mtu */
@@ -14630,7 +14938,8 @@  build_lrouter_ingress_nat_check_pkt_len(struct lflow_table *lflows,
                                             COPP_ICMP6_ERR,
                                             od->nbr->copp,
                                             meter_groups),
-                                      &nat->header_);
+                                      &nat->header_,
+                                      lflow_ref);
         }
 }
 
@@ -14641,7 +14950,8 @@  build_lrouter_ingress_flow(struct lflow_table *lflows,
                            struct ds *actions, struct eth_addr mac,
                            bool distributed_nat, bool is_v6,
                            struct ovn_port *l3dgw_port,
-                           const struct shash *meter_groups)
+                           const struct shash *meter_groups,
+                           struct lflow_ref *lflow_ref)
 {
     if (od->n_l3dgw_ports && !strcmp(nat->type, "snat")) {
         ds_clear(match);
@@ -14651,7 +14961,7 @@  build_lrouter_ingress_flow(struct lflow_table *lflows,
             is_v6 ? "ip6.src" : "ip4.src", nat->external_ip);
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT,
                                 120, ds_cstr(match), "next;",
-                                &nat->header_);
+                                &nat->header_, lflow_ref);
     }
     /* Logical router ingress table 0:
     * For NAT on a distributed router, add rules allowing
@@ -14675,12 +14985,14 @@  build_lrouter_ingress_flow(struct lflow_table *lflows,
         build_gateway_mtu_flow(lflows, l3dgw_port,
                                S_ROUTER_IN_ADMISSION, 50, 55,
                                match, actions, &nat->header_,
+                               lflow_ref,
                                REG_INPORT_ETH_ADDR " = %s; next;",
                                l3dgw_port->lrp_networks.ea_s);
         if (gw_mtu) {
             build_lrouter_ingress_nat_check_pkt_len(lflows, nat, od, is_v6,
                                                     match, actions, gw_mtu,
-                                                    l3dgw_port, meter_groups);
+                                                    l3dgw_port, meter_groups,
+                                                    lflow_ref);
         }
     }
 }
@@ -14815,27 +15127,33 @@  lrouter_check_nat_entry(const struct ovn_datapath *od,
 
 /* NAT, Defrag and load balancing. */
 static void build_lr_nat_defrag_and_lb_default_flows(struct ovn_datapath *od,
-                                                struct lflow_table *lflows)
+                                                struct lflow_table *lflows,
+                                                struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
 
     /* Packets are allowed by default. */
-    ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 0, "1", "next;");
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, 0, "1", "next;", lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 0, "1", "next;", lflow_ref);
     ovn_lflow_add(lflows, od, S_ROUTER_OUT_CHECK_DNAT_LOCAL, 0, "1",
-                  REGBIT_DST_NAT_IP_LOCAL" = 0; next;");
-    ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_SNAT, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 0, "1", "next;");
-    ovn_lflow_add(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 0, "1", "next;");
+                  REGBIT_DST_NAT_IP_LOCAL" = 0; next;", lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 0, "1", "next;", lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 0, "1", "next;", lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 0, "1", "next;", lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_SNAT, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 0, "1", "next;",
+                  lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 0, "1", "next;",
+                  lflow_ref);
 
     /* Send the IPv6 NS packets to next table. When ovn-controller
      * generates IPv6 NS (for the action - nd_ns{}), the injected
      * packet would go through conntrack - which is not required. */
-    ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 120, "nd_ns", "next;");
+    ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 120, "nd_ns", "next;",
+                  lflow_ref);
 }
 
 static void
@@ -14845,7 +15163,8 @@  build_lrouter_nat_defrag_and_lb(
     const struct hmap *ls_ports, const struct hmap *lr_ports,
     struct ds *match, struct ds *actions,
     const struct shash *meter_groups,
-    const struct chassis_features *features)
+    const struct chassis_features *features,
+    struct lflow_ref *lflow_ref)
 {
     const struct ovn_datapath *od = lr_sful_rec->od;
     ovs_assert(od->nbr);
@@ -14870,16 +15189,18 @@  build_lrouter_nat_defrag_and_lb(
 
         ds_put_format(match, " && %s.skip_snat == 1", ct_flag_reg);
         ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match),
-                      "flags.skip_snat_for_lb = 1; ct_commit_nat;");
+                      "flags.skip_snat_for_lb = 1; ct_commit_nat;",
+                      lflow_ref);
 
         ds_truncate(match, match_len);
         ds_put_format(match, " && %s.force_snat == 1", ct_flag_reg);
         ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match),
-                      "flags.force_snat_for_lb = 1; ct_commit_nat;");
+                      "flags.force_snat_for_lb = 1; ct_commit_nat;",
+                      lflow_ref);
 
         ds_truncate(match, match_len);
         ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, ds_cstr(match),
-                      "ct_commit_nat;");
+                      "ct_commit_nat;", lflow_ref);
     }
 
     /* Ingress DNAT (Priority 50/70).
@@ -14896,16 +15217,18 @@  build_lrouter_nat_defrag_and_lb(
 
         ds_put_format(match, " && %s.skip_snat == 1", ct_flag_reg);
         ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match),
-                      "flags.skip_snat_for_lb = 1; next;");
+                      "flags.skip_snat_for_lb = 1; next;",
+                      lflow_ref);
 
         ds_truncate(match, match_len);
         ds_put_format(match, " && %s.force_snat == 1", ct_flag_reg);
         ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match),
-                      "flags.force_snat_for_lb = 1; next;");
+                      "flags.force_snat_for_lb = 1; next;",
+                      lflow_ref);
 
         ds_truncate(match, match_len);
         ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, ds_cstr(match),
-                      "next;");
+                      "next;", lflow_ref);
     }
 
     /* If the router has load balancer or DNAT rules, re-circulate every packet
@@ -14920,11 +15243,14 @@  build_lrouter_nat_defrag_and_lb(
     if (od->is_gw_router && (od->nbr->n_nat || lr_sful_rec->has_lb_vip)) {
         /* Do not send ND or ICMP packets to connection tracking. */
         ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100,
-                      "nd || nd_rs || nd_ra", "next;");
+                      "nd || nd_rs || nd_ra", "next;",
+                      lflow_ref);
         ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 50,
-                      "ip", "flags.loopback = 1; ct_dnat;");
+                      "ip", "flags.loopback = 1; ct_dnat;",
+                      lflow_ref);
         ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 50,
-                      "ip && ct.new", "ct_commit { } ; next; ");
+                      "ip && ct.new", "ct_commit { } ; next; ",
+                      lflow_ref);
     }
 
     /* NAT rules are only valid on Gateway routers and routers with
@@ -14973,19 +15299,20 @@  build_lrouter_nat_defrag_and_lb(
         if (stateless) {
             build_lrouter_in_unsnat_stateless_flow(lflows, od, nat, match,
                                                    distributed_nat, is_v6,
-                                                   l3dgw_port);
+                                                   l3dgw_port, lflow_ref);
         } else if (lrouter_use_common_zone(od)) {
             build_lrouter_in_unsnat_in_czone_flow(lflows, od, nat, match,
                                                   distributed_nat, is_v6,
-                                                  l3dgw_port);
+                                                  l3dgw_port, lflow_ref);
         } else {
             build_lrouter_in_unsnat_flow(lflows, od, nat, match,
-                                         distributed_nat, is_v6, l3dgw_port);
+                                         distributed_nat, is_v6, l3dgw_port,
+                                         lflow_ref);
         }
         /* S_ROUTER_IN_DNAT */
         build_lrouter_in_dnat_flow(lflows, od, lrnat_rec, nat, match, actions,
                                    distributed_nat, cidr_bits, is_v6,
-                                   l3dgw_port, stateless);
+                                   l3dgw_port, stateless, lflow_ref);
 
         /* ARP resolve for NAT IPs. */
         if (od->is_gw_router) {
@@ -15008,7 +15335,8 @@  build_lrouter_nat_defrag_and_lb(
                                         S_ROUTER_IN_ARP_RESOLVE,
                                         150, ds_cstr(match),
                                         debug_drop_action(),
-                                        &nat->header_);
+                                        &nat->header_,
+                                        lflow_ref);
                 /* Now for packets coming from other (downlink) LRPs, allow ARP
                  * resolve for the NAT IP, so that such packets can be
                  * forwarded for E/W NAT. */
@@ -15027,7 +15355,8 @@  build_lrouter_nat_defrag_and_lb(
                                         S_ROUTER_IN_ARP_RESOLVE,
                                         100, ds_cstr(match),
                                         ds_cstr(actions),
-                                        &nat->header_);
+                                        &nat->header_,
+                                        lflow_ref);
                 if (od->redirect_bridged && distributed_nat) {
                     ds_clear(match);
                     ds_put_format(
@@ -15048,7 +15377,8 @@  build_lrouter_nat_defrag_and_lb(
                     ovn_lflow_add_with_hint(lflows, od,
                                             S_ROUTER_IN_ARP_RESOLVE, 90,
                                             ds_cstr(match), ds_cstr(actions),
-                                            &nat->header_);
+                                            &nat->header_,
+                                            lflow_ref);
                 }
                 sset_add(&nat_entries, nat->external_ip);
             }
@@ -15058,13 +15388,13 @@  build_lrouter_nat_defrag_and_lb(
             /* S_ROUTER_OUT_DNAT_LOCAL */
             build_lrouter_out_is_dnat_local(lflows, od, nat, match, actions,
                                             distributed_nat, is_v6,
-                                            l3dgw_port);
+                                            l3dgw_port, lflow_ref);
         }
 
         /* S_ROUTER_OUT_UNDNAT */
         build_lrouter_out_undnat_flow(lflows, od, nat, match, actions,
                                       distributed_nat, mac, is_v6, l3dgw_port,
-                                      stateless);
+                                      stateless, lflow_ref);
         /* S_ROUTER_OUT_SNAT
          * Egress SNAT table: Packets enter the egress pipeline with
          * source ip address that needs to be SNATted to a external ip
@@ -15073,21 +15403,22 @@  build_lrouter_nat_defrag_and_lb(
             build_lrouter_out_snat_stateless_flow(lflows, od, nat, match,
                                                   actions, distributed_nat,
                                                   mac, cidr_bits, is_v6,
-                                                  l3dgw_port);
+                                                  l3dgw_port, lflow_ref);
         } else if (lrouter_use_common_zone(od)) {
             build_lrouter_out_snat_in_czone_flow(lflows, od, nat, match,
                                                  actions, distributed_nat, mac,
-                                                 cidr_bits, is_v6, l3dgw_port);
+                                                 cidr_bits, is_v6, l3dgw_port,
+                                                 lflow_ref);
         } else {
             build_lrouter_out_snat_flow(lflows, od, nat, match, actions,
                                         distributed_nat, mac, cidr_bits, is_v6,
-                                        l3dgw_port);
+                                        l3dgw_port, lflow_ref);
         }
 
         /* S_ROUTER_IN_ADMISSION - S_ROUTER_IN_IP_INPUT */
         build_lrouter_ingress_flow(lflows, od, nat, match, actions, mac,
                                    distributed_nat, is_v6, l3dgw_port,
-                                   meter_groups);
+                                   meter_groups, lflow_ref);
 
         /* Ingress Gateway Redirect Table: For NAT on a distributed
          * router, add flows that are specific to a NAT rule.  These
@@ -15114,7 +15445,8 @@  build_lrouter_nat_defrag_and_lb(
             if (op && op->nbsp && !strcmp(op->nbsp->type, "virtual")) {
                 ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT,
                                         80, ds_cstr(match),
-                                        debug_drop_action(), &nat->header_);
+                                        debug_drop_action(), &nat->header_,
+                                        lflow_ref);
             }
             ds_put_format(match, " && is_chassis_resident(\"%s\")",
                           nat->logical_port);
@@ -15124,7 +15456,8 @@  build_lrouter_nat_defrag_and_lb(
                           nat->external_ip);
             ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT,
                                     100, ds_cstr(match),
-                                    ds_cstr(actions), &nat->header_);
+                                    ds_cstr(actions), &nat->header_,
+                                    lflow_ref);
         }
 
         /* Egress Loopback table: For NAT on a distributed router.
@@ -15165,7 +15498,7 @@  build_lrouter_nat_defrag_and_lb(
                           ovn_stage_get_table(S_ROUTER_IN_ADMISSION));
             ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_EGR_LOOP, 100,
                                     ds_cstr(match), ds_cstr(actions),
-                                    &nat->header_);
+                                    &nat->header_, lflow_ref);
         }
     }
 
@@ -15185,7 +15518,7 @@  build_lrouter_nat_defrag_and_lb(
         ds_put_cstr(actions, REGBIT_DST_NAT_IP_LOCAL" = 1; next;");
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_CHECK_DNAT_LOCAL,
                                 50, ds_cstr(match), ds_cstr(actions),
-                                &od->nbr->header_);
+                                &od->nbr->header_, lflow_ref);
 
     }
 
@@ -15195,22 +15528,24 @@  build_lrouter_nat_defrag_and_lb(
             if (lrnat_rec->dnat_force_snat_addrs.n_ipv4_addrs) {
                 build_lrouter_force_snat_flows(lflows, od, "4",
                     lrnat_rec->dnat_force_snat_addrs.ipv4_addrs[0].addr_s,
-                    "dnat");
+                    "dnat", lflow_ref);
             }
             if (lrnat_rec->dnat_force_snat_addrs.n_ipv6_addrs) {
                 build_lrouter_force_snat_flows(lflows, od, "6",
                     lrnat_rec->dnat_force_snat_addrs.ipv6_addrs[0].addr_s,
-                    "dnat");
+                    "dnat", lflow_ref);
             }
         }
         if (lb_force_snat_ip) {
             if (lrnat_rec->lb_force_snat_addrs.n_ipv4_addrs) {
                 build_lrouter_force_snat_flows(lflows, od, "4",
-                    lrnat_rec->lb_force_snat_addrs.ipv4_addrs[0].addr_s, "lb");
+                    lrnat_rec->lb_force_snat_addrs.ipv4_addrs[0].addr_s, "lb",
+                    lflow_ref);
             }
             if (lrnat_rec->lb_force_snat_addrs.n_ipv6_addrs) {
                 build_lrouter_force_snat_flows(lflows, od, "6",
-                    lrnat_rec->lb_force_snat_addrs.ipv6_addrs[0].addr_s, "lb");
+                    lrnat_rec->lb_force_snat_addrs.ipv6_addrs[0].addr_s, "lb",
+                    lflow_ref);
             }
         }
     }
@@ -15248,7 +15583,8 @@  build_lbnat_lflows_iterate_by_lsp(struct ovn_port *op,
                                   const struct hmap *lr_ports,
                                   struct ds *match,
                                   struct ds *actions,
-                                  struct lflow_table *lflows)
+                                  struct lflow_table *lflows,
+                                  struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbsp);
 
@@ -15263,7 +15599,7 @@  build_lbnat_lflows_iterate_by_lsp(struct ovn_port *op,
 
     build_lsp_lflows_for_lbnats(op, op->peer, lr_sful_rec,
                                 lr_sful_table, lr_ports, lflows,
-                                match, actions, op->stateful_lflow_ref);
+                                match, actions, lflow_ref);
 }
 
 static void
@@ -15271,7 +15607,8 @@  build_lrp_lflows_for_lbnats(struct ovn_port *op,
                             const struct lr_stateful_record *lr_sful_rec,
                             const struct shash *meter_groups,
                             struct ds *match, struct ds *actions,
-                            struct lflow_table *lflows)
+                            struct lflow_table *lflows,
+                            struct lflow_ref *lflow_ref)
 {
     /* Drop IP traffic destined to router owned IPs except if the IP is
      * also a SNAT IP. Those are dropped later, in stage
@@ -15284,7 +15621,8 @@  build_lrp_lflows_for_lbnats(struct ovn_port *op,
      */
     if (!lr_sful_rec->lrnat_rec->lb_force_snat_router_ip) {
         build_lrouter_drop_own_dest(op, lr_sful_rec,
-                                    S_ROUTER_IN_IP_INPUT, 60, false, lflows);
+                                    S_ROUTER_IN_IP_INPUT, 60, false,
+                                    lflows, lflow_ref);
     }
 
     /* Drop IP traffic destined to router owned IPs. Part of it is dropped
@@ -15294,12 +15632,14 @@  build_lrp_lflows_for_lbnats(struct ovn_port *op,
      * Priority 2.
      */
     build_lrouter_drop_own_dest(op, lr_sful_rec,
-                                S_ROUTER_IN_ARP_RESOLVE, 2, true, lflows);
+                                S_ROUTER_IN_ARP_RESOLVE, 2, true,
+                                lflows, lflow_ref);
 
     build_lrouter_ipv4_ip_input_for_lbnats(op, lflows, lr_sful_rec,
-                                           match, meter_groups);
+                                           match, meter_groups,
+                                           lflow_ref);
     build_lrouter_force_snat_flows_op(op, lr_sful_rec->lrnat_rec, lflows,
-                                      match, actions);
+                                      match, actions, lflow_ref);
 }
 
 static void
@@ -15308,7 +15648,8 @@  build_lbnat_lflows_iterate_by_lrp(struct ovn_port *op,
                                   const struct shash *meter_groups,
                                   struct ds *match,
                                   struct ds *actions,
-                                  struct lflow_table *lflows)
+                                  struct lflow_table *lflows,
+                                  struct lflow_ref *lflow_ref)
 {
     ovs_assert(op->nbrp);
 
@@ -15318,7 +15659,7 @@  build_lbnat_lflows_iterate_by_lrp(struct ovn_port *op,
     ovs_assert(lr_sful_rec);
 
     build_lrp_lflows_for_lbnats(op, lr_sful_rec, meter_groups, match,
-                                actions, lflows);
+                                actions, lflows, lflow_ref);
 }
 
 static void
@@ -15332,13 +15673,16 @@  build_lr_stateful_flows(const struct lr_stateful_record *lr_sful_rec,
                         const struct chassis_features *features)
 {
     build_lrouter_nat_defrag_and_lb(lr_sful_rec, lflows, ls_ports, lr_ports,
-                                    match, actions, meter_groups, features);
+                                    match, actions, meter_groups, features,
+                                    NULL);
     build_lr_gateway_redirect_flows_for_nats(lr_sful_rec->od,
                                              lr_sful_rec->lrnat_rec, lflows,
-                                             match, actions);
+                                             match, actions,
+                                             NULL);
     build_lrouter_arp_nd_for_datapath(lr_sful_rec->od,
                                       lr_sful_rec->lrnat_rec, lflows,
-                                      meter_groups);
+                                      meter_groups,
+                                      NULL);
 }
 
 static void
@@ -15350,11 +15694,13 @@  build_ls_stateful_flows(const struct ls_stateful_record *ls_stateful_rec,
 {
     ovs_assert(ls_stateful_rec->od);
 
-    build_ls_stateful_rec_pre_acls(ls_stateful_rec, ls_pgs, lflows);
-    build_ls_stateful_rec_pre_lb(ls_stateful_rec, lflows);
-    build_acl_hints(ls_stateful_rec, features, lflows);
-    build_acls(ls_stateful_rec, features, lflows, ls_pgs, meter_groups);
-    build_lb_hairpin(ls_stateful_rec, lflows);
+    build_ls_stateful_rec_pre_acls(ls_stateful_rec, ls_pgs, lflows,
+                                   NULL);
+    build_ls_stateful_rec_pre_lb(ls_stateful_rec, lflows, NULL);
+    build_acl_hints(ls_stateful_rec, features, lflows, NULL);
+    build_acls(ls_stateful_rec, features, lflows, ls_pgs, meter_groups,
+               NULL);
+    build_lb_hairpin(ls_stateful_rec, lflows, NULL);
 }
 
 struct lswitch_flow_build_info {
@@ -15390,19 +15736,20 @@  build_lswitch_and_lrouter_iterate_by_ls(struct ovn_datapath *od,
 {
     ovs_assert(od->nbs);
     build_lswitch_lflows_pre_acl_and_acl(od, lsi->features, lsi->lflows,
-                                         lsi->meter_groups);
-
-    build_fwd_group_lflows(od, lsi->lflows);
-    build_lswitch_lflows_admission_control(od, lsi->lflows);
-    build_lswitch_learn_fdb_od(od, lsi->lflows);
-    build_lswitch_arp_nd_responder_default(od, lsi->lflows);
-    build_lswitch_dns_lookup_and_response(od, lsi->lflows, lsi->meter_groups);
-    build_lswitch_dhcp_and_dns_defaults(od, lsi->lflows);
+                                         lsi->meter_groups, NULL);
+
+    build_fwd_group_lflows(od, lsi->lflows, NULL);
+    build_lswitch_lflows_admission_control(od, lsi->lflows, NULL);
+    build_lswitch_learn_fdb_od(od, lsi->lflows, NULL);
+    build_lswitch_arp_nd_responder_default(od, lsi->lflows, NULL);
+    build_lswitch_dns_lookup_and_response(od, lsi->lflows, lsi->meter_groups,
+                                          NULL);
+    build_lswitch_dhcp_and_dns_defaults(od, lsi->lflows, NULL);
     build_lswitch_destination_lookup_bmcast(od, lsi->lflows, &lsi->actions,
-                                            lsi->meter_groups);
-    build_lswitch_output_port_sec_od(od, lsi->lflows);
-    build_lswitch_lb_affinity_default_flows(od, lsi->lflows);
-    build_lswitch_lflows_l2_unknown(od, lsi->lflows);
+                                            lsi->meter_groups, NULL);
+    build_lswitch_output_port_sec_od(od, lsi->lflows, NULL);
+    build_lswitch_lb_affinity_default_flows(od, lsi->lflows, NULL);
+    build_lswitch_lflows_l2_unknown(od, lsi->lflows, NULL);
 }
 
 /* Helper function to combine all lflow generation which is iterated by
@@ -15413,29 +15760,34 @@  build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od,
                                         struct lswitch_flow_build_info *lsi)
 {
     ovs_assert(od->nbr);
-    build_adm_ctrl_flows_for_lrouter(od, lsi->lflows);
+    build_adm_ctrl_flows_for_lrouter(od, lsi->lflows, NULL);
     build_neigh_learning_flows_for_lrouter(od, lsi->lflows, &lsi->match,
-                                           &lsi->actions, lsi->meter_groups);
-    build_ND_RA_flows_for_lrouter(od, lsi->lflows);
-    build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows);
+                                           &lsi->actions,
+                                           lsi->meter_groups, NULL);
+    build_ND_RA_flows_for_lrouter(od, lsi->lflows, NULL);
+    build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows, NULL);
     build_static_route_flows_for_lrouter(od, lsi->features,
                                          lsi->lflows, lsi->lr_ports,
-                                         lsi->bfd_connections);
+                                         lsi->bfd_connections,
+                                         NULL);
     build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match,
-                                         &lsi->actions);
-    build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports);
-    build_arp_resolve_flows_for_lrouter(od, lsi->lflows);
+                                         &lsi->actions, NULL);
+    build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports,
+                                           NULL);
+    build_arp_resolve_flows_for_lrouter(od, lsi->lflows, NULL);
     build_check_pkt_len_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports,
                                           &lsi->match, &lsi->actions,
-                                          lsi->meter_groups);
+                                          lsi->meter_groups, NULL);
     build_gateway_redirect_flows_for_lrouter(od, lsi->lflows, &lsi->match,
-                                             &lsi->actions);
+                                             &lsi->actions, NULL);
     build_arp_request_flows_for_lrouter(od, lsi->lflows, &lsi->match,
-                                        &lsi->actions, lsi->meter_groups);
-    build_misc_local_traffic_drop_flows_for_lrouter(od, lsi->lflows);
+                                        &lsi->actions,
+                                        lsi->meter_groups,
+                                        NULL);
+    build_misc_local_traffic_drop_flows_for_lrouter(od, lsi->lflows, NULL);
 
-    build_lr_nat_defrag_and_lb_default_flows(od, lsi->lflows);
-    build_lrouter_lb_affinity_default_flows(od, lsi->lflows);
+    build_lr_nat_defrag_and_lb_default_flows(od, lsi->lflows, NULL);
+    build_lrouter_lb_affinity_default_flows(od, lsi->lflows, NULL);
 }
 
 /* Helper function to combine all lflow generation which is iterated by logical
@@ -15477,22 +15829,26 @@  build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op,
     ovs_assert(op->nbrp);
 
     build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
-                                          &lsi->actions);
+                                          &lsi->actions, op->lflow_ref);
     build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
-                                                &lsi->actions);
-    build_ip_routing_flows_for_lrp(op, lsi->lflows);
+                                                &lsi->actions, op->lflow_ref);
+    build_ip_routing_flows_for_lrp(op, lsi->lflows, op->lflow_ref);
     build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
-                                       &lsi->actions, lsi->meter_groups);
+                                       &lsi->actions, lsi->meter_groups,
+                                       op->lflow_ref);
     build_arp_resolve_flows_for_lrp(op, lsi->lflows,
-                                    &lsi->match, &lsi->actions);
+                                    &lsi->match, &lsi->actions, op->lflow_ref);
     build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
-                                                 &lsi->actions);
-    build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match);
+                                                 &lsi->actions,
+                                                 op->lflow_ref);
+    build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
+                                              op->lflow_ref);
     build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows,
                                             &lsi->match, &lsi->actions,
-                                            lsi->meter_groups);
+                                            lsi->meter_groups,
+                                            op->lflow_ref);
     build_lrouter_ipv4_ip_input(op, lsi->lflows, &lsi->match, &lsi->actions,
-                                lsi->meter_groups);
+                                lsi->meter_groups, op->lflow_ref);
 }
 
 static void *
@@ -15560,7 +15916,8 @@  build_lflows_thread(void *arg)
                                                       lsi->lr_ports,
                                                       &lsi->match,
                                                       &lsi->actions,
-                                                      lsi->lflows);
+                                                      lsi->lflows,
+                                                      op->stateful_lflow_ref);
                 }
             }
             for (bnum = control->id;
@@ -15577,7 +15934,8 @@  build_lflows_thread(void *arg)
                                                       lsi->meter_groups,
                                                       &lsi->match,
                                                       &lsi->actions,
-                                                      lsi->lflows);
+                                                      lsi->lflows,
+                                                      op->stateful_lflow_ref);
                 }
             }
             for (bnum = control->id;
@@ -15593,23 +15951,27 @@  build_lflows_thread(void *arg)
                                                          lsi->ls_ports,
                                                          lsi->lflows,
                                                          &lsi->match,
-                                                         &lsi->actions);
+                                                         &lsi->actions,
+                                                         NULL);
                     build_lrouter_defrag_flows_for_lb(lb_dps, lsi->lflows,
                                                       lsi->lr_datapaths,
-                                                      &lsi->match);
+                                                      &lsi->match,
+                                                      NULL);
                     build_lrouter_flows_for_lb(lb_dps, lsi->lflows,
                                                lsi->meter_groups,
                                                lsi->lr_datapaths,
                                                lsi->lr_sful_table,
                                                lsi->features,
                                                lsi->svc_monitor_map,
-                                               &lsi->match, &lsi->actions);
+                                               &lsi->match, &lsi->actions,
+                                               NULL);
                     build_lswitch_flows_for_lb(lb_dps, lsi->lflows,
                                                lsi->meter_groups,
                                                lsi->ls_datapaths,
                                                lsi->features,
                                                lsi->svc_monitor_map,
-                                               &lsi->match, &lsi->actions);
+                                               &lsi->match, &lsi->actions,
+                                               NULL);
                 }
             }
             for (bnum = control->id;
@@ -15654,7 +16016,7 @@  build_lflows_thread(void *arg)
                     }
                     build_lswitch_ip_mcast_igmp_mld(igmp_group, lsi->lflows,
                                                     &lsi->match,
-                                                    &lsi->actions);
+                                                    &lsi->actions, NULL);
                 }
             }
         }
@@ -15807,7 +16169,8 @@  build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths,
                                                      lsi.lflows);
             build_lbnat_lflows_iterate_by_lsp(op, lsi.lr_sful_table, lsi.lr_ports,
                                               &lsi.match, &lsi.actions,
-                                              lsi.lflows);
+                                              lsi.lflows,
+                                              op->stateful_lflow_ref);
         }
         HMAP_FOR_EACH (op, key_node, lr_ports) {
             build_lswitch_and_lrouter_iterate_by_lrp(op, &lsi);
@@ -15815,24 +16178,29 @@  build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths,
                                               lsi.meter_groups,
                                               &lsi.match,
                                               &lsi.actions,
-                                              lsi.lflows);
+                                              lsi.lflows,
+                                              op->stateful_lflow_ref);
         }
         stopwatch_stop(LFLOWS_PORTS_STOPWATCH_NAME, time_msec());
         stopwatch_start(LFLOWS_LBS_STOPWATCH_NAME, time_msec());
         HMAP_FOR_EACH (lb_dps, hmap_node, lb_dps_map) {
             build_lswitch_arp_nd_service_monitor(lb_dps->lb, lsi.ls_ports,
                                                  lsi.lflows, &lsi.actions,
-                                                 &lsi.match);
+                                                 &lsi.match,
+                                                 NULL);
             build_lrouter_defrag_flows_for_lb(lb_dps, lsi.lflows,
-                                              lsi.lr_datapaths, &lsi.match);
+                                              lsi.lr_datapaths, &lsi.match,
+                                              NULL);
             build_lrouter_flows_for_lb(lb_dps, lsi.lflows, lsi.meter_groups,
                                        lsi.lr_datapaths, lsi.lr_sful_table,
                                        lsi.features, lsi.svc_monitor_map,
-                                       &lsi.match, &lsi.actions);
+                                       &lsi.match, &lsi.actions,
+                                       NULL);
             build_lswitch_flows_for_lb(lb_dps, lsi.lflows, lsi.meter_groups,
                                        lsi.ls_datapaths, lsi.features,
                                        lsi.svc_monitor_map,
-                                       &lsi.match, &lsi.actions);
+                                       &lsi.match, &lsi.actions,
+                                       NULL);
         }
         stopwatch_stop(LFLOWS_LBS_STOPWATCH_NAME, time_msec());
 
@@ -15854,7 +16222,8 @@  build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths,
             build_lswitch_ip_mcast_igmp_mld(igmp_group,
                                             lsi.lflows,
                                             &lsi.actions,
-                                            &lsi.match);
+                                            &lsi.match,
+                                            NULL);
         }
         stopwatch_stop(LFLOWS_IGMP_STOPWATCH_NAME, time_msec());