diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index 6384651..5e4bd5b 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -520,6 +520,9 @@ struct ovnact_encode_params {
     /* A struct to figure out the meter_id for meter actions. */
     struct ovn_extend_table *meter_table;
 
+    /* The logical flow uuid that drove this action. */
+    struct uuid lflow_uuid;
+
     /* OVN maps each logical flow table (ltable), one-to-one, onto a physical
      * OpenFlow flow table (ptable).  A number of parameters describe this
      * mapping and data related to flow tables:
diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c
index 8db8192..5f34b3a 100644
--- a/ovn/controller/lflow.c
+++ b/ovn/controller/lflow.c
@@ -62,7 +62,7 @@ struct condition_aux {
     const struct sset *active_tunnels;
 };
 
-static void consider_logical_flow(
+static bool consider_logical_flow(
     struct ovsdb_idl_index *sbrec_chassis_by_name,
     struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath,
     struct ovsdb_idl_index *sbrec_port_binding_by_name,
@@ -76,10 +76,10 @@ static void consider_logical_flow(
     const struct shash *port_groups,
     const struct sset *active_tunnels,
     const struct sset *local_lport_ids,
-    uint32_t *conj_id_ofs,
-    struct hmap *flow_table,
+    struct ovn_desired_flow_table *,
     struct ovn_extend_table *group_table,
-    struct ovn_extend_table *meter_table);
+    struct ovn_extend_table *meter_table,
+    uint32_t *conj_id_ofs);
 
 static bool
 lookup_port_cb(const void *aux_, const char *port_name, unsigned int *portp)
@@ -153,11 +153,11 @@ add_logical_flows(
     const struct shash *port_groups,
     const struct sset *active_tunnels,
     const struct sset *local_lport_ids,
-    struct hmap *flow_table,
+    struct ovn_desired_flow_table *flow_table,
     struct ovn_extend_table *group_table,
-    struct ovn_extend_table *meter_table)
+    struct ovn_extend_table *meter_table,
+    uint32_t *conj_id_ofs)
 {
-    uint32_t conj_id_ofs = 1;
     const struct sbrec_logical_flow *lflow;
 
     struct hmap dhcp_opts = HMAP_INITIALIZER(&dhcp_opts);
@@ -180,14 +180,19 @@ add_logical_flows(
     nd_ra_opts_init(&nd_ra_opts);
 
     SBREC_LOGICAL_FLOW_TABLE_FOR_EACH (lflow, logical_flow_table) {
-        consider_logical_flow(sbrec_chassis_by_name,
-                              sbrec_multicast_group_by_name_datapath,
-                              sbrec_port_binding_by_name,
-                              lflow, local_datapaths,
-                              chassis, &dhcp_opts, &dhcpv6_opts, &nd_ra_opts,
-                              addr_sets, port_groups, active_tunnels,
-                              local_lport_ids, &conj_id_ofs,
-                              flow_table, group_table, meter_table);
+        if (!consider_logical_flow(sbrec_chassis_by_name,
+                                   sbrec_multicast_group_by_name_datapath,
+                                   sbrec_port_binding_by_name,
+                                   lflow, local_datapaths,
+                                   chassis, &dhcp_opts, &dhcpv6_opts, &nd_ra_opts,
+                                   addr_sets, port_groups, active_tunnels,
+                                   local_lport_ids, flow_table,
+                                   group_table, meter_table,
+                                   conj_id_ofs)) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
+            VLOG_ERR_RL(&rl, "Conjunction id overflow when processing lflow "
+                        UUID_FMT, UUID_ARGS(&lflow->header_.uuid));
+        }
     }
 
     dhcp_opts_destroy(&dhcp_opts);
@@ -195,7 +200,102 @@ add_logical_flows(
     nd_ra_opts_destroy(&nd_ra_opts);
 }
 
-static void
+bool
+lflow_handle_changed_flows(
+    struct ovsdb_idl_index *sbrec_chassis_by_name,
+    struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath,
+    struct ovsdb_idl_index *sbrec_port_binding_by_name,
+    const struct sbrec_dhcp_options_table *dhcp_options_table,
+    const struct sbrec_dhcpv6_options_table *dhcpv6_options_table,
+    const struct sbrec_logical_flow_table *logical_flow_table,
+    const struct hmap *local_datapaths,
+    const struct sbrec_chassis *chassis,
+    const struct shash *addr_sets,
+    const struct shash *port_groups,
+    const struct sset *active_tunnels,
+    const struct sset *local_lport_ids,
+    struct ovn_desired_flow_table *flow_table,
+    struct ovn_extend_table *group_table,
+    struct ovn_extend_table *meter_table,
+    uint32_t *conj_id_ofs)
+{
+    bool ret = true;
+    const struct sbrec_logical_flow *lflow;
+
+    struct hmap dhcp_opts = HMAP_INITIALIZER(&dhcp_opts);
+    struct hmap dhcpv6_opts = HMAP_INITIALIZER(&dhcpv6_opts);
+    const struct sbrec_dhcp_options *dhcp_opt_row;
+    SBREC_DHCP_OPTIONS_TABLE_FOR_EACH (dhcp_opt_row, dhcp_options_table) {
+        dhcp_opt_add(&dhcp_opts, dhcp_opt_row->name, dhcp_opt_row->code,
+                     dhcp_opt_row->type);
+    }
+
+
+    const struct sbrec_dhcpv6_options *dhcpv6_opt_row;
+    SBREC_DHCPV6_OPTIONS_TABLE_FOR_EACH (dhcpv6_opt_row,
+                                         dhcpv6_options_table) {
+       dhcp_opt_add(&dhcpv6_opts, dhcpv6_opt_row->name, dhcpv6_opt_row->code,
+                    dhcpv6_opt_row->type);
+    }
+
+    struct hmap nd_ra_opts = HMAP_INITIALIZER(&nd_ra_opts);
+    nd_ra_opts_init(&nd_ra_opts);
+
+    /* Handle removed flows first, and then other flows, so that when
+     * the flows being added and removed have same match conditions
+     * can be processed in the proper order */
+    SBREC_LOGICAL_FLOW_TABLE_FOR_EACH_TRACKED (lflow, logical_flow_table) {
+        /* Remove any flows that should be removed. */
+        if (sbrec_logical_flow_is_deleted(lflow)) {
+            VLOG_DBG("handle deleted lflow "UUID_FMT,
+                     UUID_ARGS(&lflow->header_.uuid));
+            ofctrl_remove_flows(flow_table, &lflow->header_.uuid);
+        }
+    }
+    SBREC_LOGICAL_FLOW_TABLE_FOR_EACH_TRACKED (lflow, logical_flow_table) {
+        if (!sbrec_logical_flow_is_deleted(lflow)) {
+            /* Now, add/modify existing flows. If the logical
+             * flow is a modification, just remove the flows
+             * for this row, and then add new flows. */
+            if (!sbrec_logical_flow_is_new(lflow)) {
+                VLOG_DBG("handle updated lflow "UUID_FMT,
+                         UUID_ARGS(&lflow->header_.uuid));
+                ofctrl_remove_flows(flow_table, &lflow->header_.uuid);
+            }
+            VLOG_DBG("handle new lflow "UUID_FMT,
+                     UUID_ARGS(&lflow->header_.uuid));
+            if (!consider_logical_flow(sbrec_chassis_by_name,
+                                       sbrec_multicast_group_by_name_datapath,
+                                       sbrec_port_binding_by_name,
+                                       lflow, local_datapaths,
+                                       chassis, &dhcp_opts, &dhcpv6_opts, &nd_ra_opts,
+                                       addr_sets, port_groups, active_tunnels,
+                                       local_lport_ids, flow_table,
+                                       group_table, meter_table,
+                                       conj_id_ofs)) {
+                ret = false;
+                break;
+            }
+        }
+    }
+    dhcp_opts_destroy(&dhcp_opts);
+    dhcp_opts_destroy(&dhcpv6_opts);
+    nd_ra_opts_destroy(&nd_ra_opts);
+    return ret;
+}
+
+static bool
+update_conj_id_ofs(uint32_t *conj_id_ofs, uint32_t n_conjs)
+{
+    if (*conj_id_ofs + n_conjs < *conj_id_ofs) {
+        /* overflow */
+        return false;
+    }
+    *conj_id_ofs += n_conjs;
+    return true;
+}
+
+static bool 
 consider_logical_flow(
     struct ovsdb_idl_index *sbrec_chassis_by_name,
     struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath,
@@ -210,20 +310,24 @@ consider_logical_flow(
     const struct shash *port_groups,
     const struct sset *active_tunnels,
     const struct sset *local_lport_ids,
-    uint32_t *conj_id_ofs,
-    struct hmap *flow_table,
+    struct ovn_desired_flow_table *flow_table,
     struct ovn_extend_table *group_table,
-    struct ovn_extend_table *meter_table)
+    struct ovn_extend_table *meter_table,
+    uint32_t *conj_id_ofs)
 {
     /* Determine translation of logical table IDs to physical table IDs. */
     bool ingress = !strcmp(lflow->pipeline, "ingress");
 
     const struct sbrec_datapath_binding *ldp = lflow->logical_datapath;
     if (!ldp) {
-        return;
+        VLOG_DBG("lflow "UUID_FMT" has no datapath binding, skip",
+                 UUID_ARGS(&lflow->header_.uuid));
+        return true;
     }
     if (!get_local_datapath(local_datapaths, ldp->tunnel_key)) {
-        return;
+        VLOG_DBG("lflow "UUID_FMT" is not for local datapath, skip",
+                 UUID_ARGS(&lflow->header_.uuid));
+        return true;
     }
 
     /* Determine translation of logical table IDs to physical table IDs. */
@@ -261,7 +365,7 @@ consider_logical_flow(
         free(error);
         ovnacts_free(ovnacts.data, ovnacts.size);
         ofpbuf_uninit(&ovnacts);
-        return;
+        return true;
     }
 
     /* Translate OVN match into table of OpenFlow matches. */
@@ -285,7 +389,7 @@ consider_logical_flow(
         free(error);
         ovnacts_free(ovnacts.data, ovnacts.size);
         ofpbuf_uninit(&ovnacts);
-        return;
+        return true;
     }
 
     struct lookup_port_aux aux = {
@@ -307,10 +411,12 @@ consider_logical_flow(
     expr_destroy(expr);
 
     if (hmap_is_empty(&matches)) {
+        VLOG_DBG("lflow "UUID_FMT" matches are empty, skip",
+                 UUID_ARGS(&lflow->header_.uuid));
         ovnacts_free(ovnacts.data, ovnacts.size);
         ofpbuf_uninit(&ovnacts);
         expr_matches_destroy(&matches);
-        return;
+        return true;
     }
 
     /* Encode OVN logical actions into OpenFlow. */
@@ -322,6 +428,7 @@ consider_logical_flow(
         .is_switch = is_switch(ldp),
         .group_table = group_table,
         .meter_table = meter_table,
+        .lflow_uuid = lflow->header_.uuid,
 
         .pipeline = ingress ? OVNACT_P_INGRESS : OVNACT_P_EGRESS,
         .ingress_ptable = OFTABLE_LOG_INGRESS_PIPELINE,
@@ -350,13 +457,18 @@ consider_logical_flow(
                 char buf[16];
                 snprintf(buf, sizeof(buf), "%"PRId64"_%"PRId64, dp_id, port_id);
                 if (!sset_contains(local_lport_ids, buf)) {
+                    VLOG_DBG("lflow "UUID_FMT
+                             " port %s in match is not local, skip",
+                             UUID_ARGS(&lflow->header_.uuid),
+                             buf);
                     continue;
                 }
             }
         }
         if (!m->n) {
             ofctrl_add_flow(flow_table, ptable, lflow->priority,
-                            lflow->header_.uuid.parts[0], &m->match, &ofpacts);
+                            lflow->header_.uuid.parts[0], &m->match, &ofpacts,
+                            &lflow->header_.uuid);
         } else {
             uint64_t conj_stubs[64 / 8];
             struct ofpbuf conj;
@@ -372,7 +484,7 @@ consider_logical_flow(
                 dst->n_clauses = src->n_clauses;
             }
             ofctrl_add_flow(flow_table, ptable, lflow->priority, 0, &m->match,
-                            &conj);
+                            &conj, &lflow->header_.uuid);
             ofpbuf_uninit(&conj);
         }
     }
@@ -380,7 +492,7 @@ consider_logical_flow(
     /* Clean up. */
     expr_matches_destroy(&matches);
     ofpbuf_uninit(&ofpacts);
-    *conj_id_ofs += n_conjs;
+    return update_conj_id_ofs(conj_id_ofs, n_conjs);
 }
 
 static void
@@ -398,7 +510,7 @@ put_load(const uint8_t *data, size_t len,
 static void
 consider_neighbor_flow(struct ovsdb_idl_index *sbrec_port_binding_by_name,
                        const struct sbrec_mac_binding *b,
-                       struct hmap *flow_table)
+                       struct ovn_desired_flow_table *flow_table)
 {
     const struct sbrec_port_binding *pb
         = lport_lookup_by_name(sbrec_port_binding_by_name, b->logical_port);
@@ -440,7 +552,8 @@ consider_neighbor_flow(struct ovsdb_idl_index *sbrec_port_binding_by_name,
     uint64_t stub[1024 / 8];
     struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub);
     put_load(mac.ea, sizeof mac.ea, MFF_ETH_DST, 0, 48, &ofpacts);
-    ofctrl_add_flow(flow_table, OFTABLE_MAC_BINDING, 100, 0, &match, &ofpacts);
+    ofctrl_add_flow(flow_table, OFTABLE_MAC_BINDING, 100, 0, &match, &ofpacts,
+                    &b->header_.uuid);
     ofpbuf_uninit(&ofpacts);
 }
 
@@ -449,7 +562,7 @@ consider_neighbor_flow(struct ovsdb_idl_index *sbrec_port_binding_by_name,
 static void
 add_neighbor_flows(struct ovsdb_idl_index *sbrec_port_binding_by_name,
                    const struct sbrec_mac_binding_table *mac_binding_table,
-                   struct hmap *flow_table)
+                   struct ovn_desired_flow_table *flow_table)
 {
     const struct sbrec_mac_binding *b;
     SBREC_MAC_BINDING_TABLE_FOR_EACH (b, mac_binding_table) {
@@ -473,9 +586,10 @@ lflow_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
           const struct shash *port_groups,
           const struct sset *active_tunnels,
           const struct sset *local_lport_ids,
-          struct hmap *flow_table,
+          struct ovn_desired_flow_table *flow_table,
           struct ovn_extend_table *group_table,
-          struct ovn_extend_table *meter_table)
+          struct ovn_extend_table *meter_table,
+          uint32_t *conj_id_ofs)
 {
     COVERAGE_INC(lflow_run);
 
@@ -485,7 +599,7 @@ lflow_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
                       dhcpv6_options_table, logical_flow_table,
                       local_datapaths, chassis, addr_sets, port_groups,
                       active_tunnels, local_lport_ids, flow_table, group_table,
-                      meter_table);
+                      meter_table, conj_id_ofs);
     add_neighbor_flows(sbrec_port_binding_by_name, mac_binding_table,
                        flow_table);
 }
diff --git a/ovn/controller/lflow.h b/ovn/controller/lflow.h
index d193381..31e34e2 100644
--- a/ovn/controller/lflow.h
+++ b/ovn/controller/lflow.h
@@ -37,6 +37,7 @@
 
 struct ovn_extend_table;
 struct ovsdb_idl_index;
+struct ovn_desired_flow_table;
 struct hmap;
 struct sbrec_chassis;
 struct sbrec_dhcp_options_table;
@@ -78,9 +79,29 @@ void lflow_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
                const struct shash *port_groups,
                const struct sset *active_tunnels,
                const struct sset *local_lport_ids,
-               struct hmap *flow_table,
+               struct ovn_desired_flow_table *,
                struct ovn_extend_table *group_table,
-               struct ovn_extend_table *meter_table);
+               struct ovn_extend_table *meter_table,
+               uint32_t *conj_id_ofs);
+
+bool lflow_handle_changed_flows(
+    struct ovsdb_idl_index *sbrec_chassis_by_name,
+    struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath,
+    struct ovsdb_idl_index *sbrec_port_binding_by_name,
+    const struct sbrec_dhcp_options_table *,
+    const struct sbrec_dhcpv6_options_table *,
+    const struct sbrec_logical_flow_table *,
+    const struct hmap *local_datapaths,
+    const struct sbrec_chassis *,
+    const struct shash *addr_sets,
+    const struct shash *port_groups,
+    const struct sset *active_tunnels,
+    const struct sset *local_lport_ids,
+    struct ovn_desired_flow_table *,
+    struct ovn_extend_table *group_table,
+    struct ovn_extend_table *meter_table,
+    uint32_t *conj_id_ofs);
+
 void lflow_destroy(void);
 
 #endif /* ovn/lflow.h */
diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c
index 134f0e5..dda486d 100644
--- a/ovn/controller/ofctrl.c
+++ b/ovn/controller/ofctrl.c
@@ -20,6 +20,7 @@
 #include "dp-packet.h"
 #include "flow.h"
 #include "hash.h"
+#include "hindex.h"
 #include "lflow.h"
 #include "ofctrl.h"
 #include "openflow/openflow.h"
@@ -52,7 +53,8 @@ VLOG_DEFINE_THIS_MODULE(ofctrl);
 
 /* An OpenFlow flow. */
 struct ovn_flow {
-    struct hmap_node hmap_node; /* For match based hashing. */
+    struct hmap_node match_hmap_node; /* For match based hashing. */
+    struct hindex_node uuid_hindex_node; /* For uuid based hashing. */
     struct ovs_list list_node; /* For handling lists of flows. */
 
     /* Key. */
@@ -61,14 +63,16 @@ struct ovn_flow {
     struct minimatch match;
 
     /* Data. */
+    struct uuid sb_uuid;
     struct ofpact *ofpacts;
     size_t ofpacts_len;
     uint64_t cookie;
 };
 
-static uint32_t ovn_flow_hash(const struct ovn_flow *);
+static uint32_t ovn_flow_match_hash(const struct ovn_flow *);
 static struct ovn_flow *ovn_flow_lookup(struct hmap *flow_table,
-                                        const struct ovn_flow *target);
+                                        const struct ovn_flow *target,
+                                        bool cmp_sb_uuid);
 static char *ovn_flow_to_string(const struct ovn_flow *);
 static void ovn_flow_log(const struct ovn_flow *, const char *action);
 static void ovn_flow_destroy(struct ovn_flow *);
@@ -146,6 +150,10 @@ static struct ovn_extend_table *meters;
  * S_CLEAR_FLOWS or S_UPDATE_FLOWS, this is really the option we have. */
 static enum mf_field_id mff_ovn_geneve;
 
+/* Indicates if flows need to be reinstalled for scenarios when ovs
+ * is restarted, even if there is no change in the desired flow table. */
+static bool need_reinstall_flows;
+
 static ovs_be32 queue_msg(struct ofpbuf *);
 
 static struct ofpbuf *encode_flow_mod(struct ofputil_flow_mod *);
@@ -154,8 +162,8 @@ static struct ofpbuf *encode_group_mod(const struct ofputil_group_mod *);
 
 static struct ofpbuf *encode_meter_mod(const struct ofputil_meter_mod *);
 
-static void ovn_flow_table_clear(struct hmap *flow_table);
-static void ovn_flow_table_destroy(struct hmap *flow_table);
+static void ovn_installed_flow_table_clear(void);
+static void ovn_installed_flow_table_destroy(void);
 
 static void ofctrl_recv(const struct ofp_header *, enum ofptype);
 
@@ -375,6 +383,7 @@ run_S_CLEAR_FLOWS(void)
 {
     VLOG_DBG("clearing all flows");
 
+    need_reinstall_flows = true;
     /* Send a flow_mod to delete all flows. */
     struct ofputil_flow_mod fm = {
         .table_id = OFPTT_ALL,
@@ -384,9 +393,6 @@ run_S_CLEAR_FLOWS(void)
     queue_msg(encode_flow_mod(&fm));
     minimatch_destroy(&fm.match);
 
-    /* Clear installed_flows, to match the state of the switch. */
-    ovn_flow_table_clear(&installed_flows);
-
     /* Send a group_mod to delete all groups. */
     struct ofputil_group_mod gm;
     memset(&gm, 0, sizeof gm);
@@ -397,6 +403,9 @@ run_S_CLEAR_FLOWS(void)
     queue_msg(encode_group_mod(&gm));
     ofputil_uninit_group_mod(&gm);
 
+    /* Clear installed_flows, to match the state of the switch. */
+    ovn_installed_flow_table_clear();
+
     /* Clear existing groups, to match the state of the switch. */
     if (groups) {
         ovn_extend_table_clear(groups, true);
@@ -580,7 +589,7 @@ void
 ofctrl_destroy(void)
 {
     rconn_destroy(swconn);
-    ovn_flow_table_destroy(&installed_flows);
+    ovn_installed_flow_table_destroy();
     rconn_packet_counter_destroy(tx_counter);
     expr_symtab_destroy(&symtab);
     shash_destroy(&symtab);
@@ -632,14 +641,17 @@ ofctrl_recv(const struct ofp_header *oh, enum ofptype type)
  * the OpenFlow table numbered 'table_id' with the given 'priority' and
  * OpenFlow 'cookie'.  The caller retains ownership of 'match' and 'actions'.
  *
+ * The flow is also added to a hash index based on sb_uuid.
+ *
  * This just assembles the desired flow table in memory.  Nothing is actually
  * sent to the switch until a later call to ofctrl_put().
  *
  * The caller should initialize its own hmap to hold the flows. */
 void
-ofctrl_add_flow(struct hmap *desired_flows,
+ofctrl_add_flow(struct ovn_desired_flow_table *flow_table,
                 uint8_t table_id, uint16_t priority, uint64_t cookie,
-                const struct match *match, const struct ofpbuf *actions)
+                const struct match *match, const struct ofpbuf *actions,
+                const struct uuid *sb_uuid)
 {
     struct ovn_flow *f = xmalloc(sizeof *f);
     f->table_id = table_id;
@@ -647,10 +659,14 @@ ofctrl_add_flow(struct hmap *desired_flows,
     minimatch_init(&f->match, match);
     f->ofpacts = xmemdup(actions->data, actions->size);
     f->ofpacts_len = actions->size;
-    f->hmap_node.hash = ovn_flow_hash(f);
+    f->sb_uuid = *sb_uuid;
+    f->match_hmap_node.hash = ovn_flow_match_hash(f);
+    f->uuid_hindex_node.hash = uuid_hash(&f->sb_uuid);
     f->cookie = cookie;
 
-    if (ovn_flow_lookup(desired_flows, f)) {
+    ovn_flow_log(f, "ofctrl_add_flow");
+
+    if (ovn_flow_lookup(&flow_table->match_flow_table, f, true)) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
         if (!VLOG_DROP_DBG(&rl)) {
             char *s = ovn_flow_to_string(f);
@@ -662,19 +678,44 @@ ofctrl_add_flow(struct hmap *desired_flows,
         return;
     }
 
-    hmap_insert(desired_flows, &f->hmap_node, f->hmap_node.hash);
+    hmap_insert(&flow_table->match_flow_table, &f->match_hmap_node,
+                f->match_hmap_node.hash);
+    hindex_insert(&flow_table->uuid_flow_table, &f->uuid_hindex_node,
+                  f->uuid_hindex_node.hash);
+}
+
+/* Removes a bundles of flows from the flow table. */
+void
+ofctrl_remove_flows(struct ovn_desired_flow_table *flow_table,
+                    const struct uuid *sb_uuid)
+{
+    struct ovn_flow *f, *next;
+    HINDEX_FOR_EACH_WITH_HASH_SAFE (f, next, uuid_hindex_node,
+                                    uuid_hash(sb_uuid),
+                                    &flow_table->uuid_flow_table) {
+        if (uuid_equals(&f->sb_uuid, sb_uuid)) {
+            ovn_flow_log(f, "ofctrl_remove_flow");
+            hmap_remove(&flow_table->match_flow_table,
+                        &f->match_hmap_node);
+            hindex_remove(&flow_table->uuid_flow_table, &f->uuid_hindex_node);
+            ovn_flow_destroy(f);
+        }
+    }
+
+    /* remove any related group and meter info */
+    ovn_extend_table_remove_desired(groups, sb_uuid);
+    ovn_extend_table_remove_desired(meters, sb_uuid);
 }
 
 
 /* ovn_flow. */
 
-/* Returns a hash of the key in 'f'. */
+/* Returns a hash of the match key in 'f'. */
 static uint32_t
-ovn_flow_hash(const struct ovn_flow *f)
+ovn_flow_match_hash(const struct ovn_flow *f)
 {
     return hash_2words((f->table_id << 16) | f->priority,
                        minimatch_hash(&f->match, 0));
-
 }
 
 /* Duplicate an ovn_flow structure. */
@@ -687,23 +728,28 @@ ofctrl_dup_flow(struct ovn_flow *src)
     minimatch_clone(&dst->match, &src->match);
     dst->ofpacts = xmemdup(src->ofpacts, src->ofpacts_len);
     dst->ofpacts_len = src->ofpacts_len;
-    dst->hmap_node.hash = ovn_flow_hash(dst);
+    dst->sb_uuid = src->sb_uuid;
+    dst->match_hmap_node.hash = ovn_flow_match_hash(dst);
+    dst->uuid_hindex_node.hash = uuid_hash(&src->sb_uuid);
     return dst;
 }
 
 /* Finds and returns an ovn_flow in 'flow_table' whose key is identical to
  * 'target''s key, or NULL if there is none. */
 static struct ovn_flow *
-ovn_flow_lookup(struct hmap *flow_table, const struct ovn_flow *target)
+ovn_flow_lookup(struct hmap *flow_table, const struct ovn_flow *target,
+                bool cmp_sb_uuid)
 {
     struct ovn_flow *f;
 
-    HMAP_FOR_EACH_WITH_HASH (f, hmap_node, target->hmap_node.hash,
+    HMAP_FOR_EACH_WITH_HASH (f, match_hmap_node, target->match_hmap_node.hash,
                              flow_table) {
         if (f->table_id == target->table_id
             && f->priority == target->priority
             && minimatch_equal(&f->match, &target->match)) {
-            return f;
+            if (!cmp_sb_uuid || uuid_equals(&target->sb_uuid, &f->sb_uuid)) {
+                return f;
+            }
         }
     }
     return NULL;
@@ -713,6 +759,7 @@ static char *
 ovn_flow_to_string(const struct ovn_flow *f)
 {
     struct ds s = DS_EMPTY_INITIALIZER;
+    ds_put_format(&s, "sb_uuid="UUID_FMT", ", UUID_ARGS(&f->sb_uuid));
     ds_put_format(&s, "table_id=%"PRIu8", ", f->table_id);
     ds_put_format(&s, "priority=%"PRIu16", ", f->priority);
     minimatch_format(&f->match, NULL, NULL, &s, OFP_DEFAULT_PRIORITY);
@@ -743,22 +790,48 @@ ovn_flow_destroy(struct ovn_flow *f)
 }
 
 /* Flow tables of struct ovn_flow. */
+void
+ovn_desired_flow_table_init(struct ovn_desired_flow_table *flow_table)
+{
+    hmap_init(&flow_table->match_flow_table);
+    hindex_init(&flow_table->uuid_flow_table);
+}
+
+void
+ovn_desired_flow_table_clear(struct ovn_desired_flow_table *flow_table)
+{
+    struct ovn_flow *f, *next;
+    HMAP_FOR_EACH_SAFE (f, next, match_hmap_node,
+                        &flow_table->match_flow_table) {
+        hmap_remove(&flow_table->match_flow_table, &f->match_hmap_node);
+        hindex_remove(&flow_table->uuid_flow_table, &f->uuid_hindex_node);
+        ovn_flow_destroy(f);
+    }
+}
+
+void
+ovn_desired_flow_table_destroy(struct ovn_desired_flow_table *flow_table)
+{
+    ovn_desired_flow_table_clear(flow_table);
+    hmap_destroy(&flow_table->match_flow_table);
+    hindex_destroy(&flow_table->uuid_flow_table);
+}
 
 static void
-ovn_flow_table_clear(struct hmap *flow_table)
+ovn_installed_flow_table_clear(void)
 {
     struct ovn_flow *f, *next;
-    HMAP_FOR_EACH_SAFE (f, next, hmap_node, flow_table) {
-        hmap_remove(flow_table, &f->hmap_node);
+    HMAP_FOR_EACH_SAFE (f, next, match_hmap_node, &installed_flows) {
+        hmap_remove(&installed_flows, &f->match_hmap_node);
         ovn_flow_destroy(f);
     }
 }
 
 static void
-ovn_flow_table_destroy(struct hmap *flow_table)
+ovn_installed_flow_table_destroy(void)
 {
-    ovn_flow_table_clear(flow_table);
-    hmap_destroy(flow_table);
+    ovn_installed_flow_table_clear();
+    hmap_destroy(&installed_flows);
 }
 
 /* Flow table update. */
@@ -823,7 +896,7 @@ add_ct_flush_zone(uint16_t zone_id, struct ovs_list *msgs)
  * in the correct state and not backlogged with existing flow_mods.  (Our
  * criteria for being backlogged appear very conservative, but the socket
  * between ovn-controller and OVS provides some buffering.) */
-bool
+static bool
 ofctrl_can_put(void)
 {
     if (state != S_UPDATE_FLOWS
@@ -838,9 +911,7 @@ ofctrl_can_put(void)
  * with ofctrl_add_flow().
  *
  * Replaces the group table and meter table on the switch, if possible, by the
- *  contents of 'groups->desired'.  Regardless of whether the group table
- * is updated, this deletes all the groups from the 'groups->desired' and frees
- * them. (The hmap itself isn't destroyed.)
+ * contents of 'desired'.
  *
  * Sends conntrack flush messages to each zone in 'pending_ct_zones' that
  * is in the CT_ZONE_OF_QUEUED state and then moves the zone into the
@@ -848,16 +919,42 @@ ofctrl_can_put(void)
  *
  * This should be called after ofctrl_run() within the main loop. */
 void
-ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
-           int64_t nb_cfg)
+ofctrl_put(struct ovn_desired_flow_table *flow_table,
+           struct shash *pending_ct_zones,
+           int64_t nb_cfg,
+           bool flow_changed)
 {
+    static bool skipped_last_time = false;
+    static int64_t old_nb_cfg = 0;
+    bool need_put = false;
+    if (flow_changed || skipped_last_time || need_reinstall_flows) {
+        need_put = true;
+    } else if (nb_cfg != old_nb_cfg) {
+        /* nb_cfg changed since last ofctrl_put() call */
+        if (cur_cfg == old_nb_cfg) {
+            /* we were up-to-date already, so just update with the
+             * new nb_cfg */
+            cur_cfg = nb_cfg;
+        } else {
+            need_put = true;
+        }
+    }
+
+    old_nb_cfg = nb_cfg;
+
+    if (!need_put) {
+        VLOG_DBG("ofctrl_put not needed");
+        return;
+    }
     if (!ofctrl_can_put()) {
-        ovn_flow_table_clear(flow_table);
-        ovn_extend_table_clear(groups, false);
-        ovn_extend_table_clear(meters, false);
+        VLOG_DBG("ofctrl_put can't be performed");
+        skipped_last_time = true;
         return;
     }
 
+    skipped_last_time = false;
+    need_reinstall_flows = false;
+
     /* OpenFlow messages to send to the switch to bring it up-to-date. */
     struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
 
@@ -921,8 +1018,9 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
      * longer desired, delete them; if any of them should have different
      * actions, update them. */
     struct ovn_flow *i, *next;
-    HMAP_FOR_EACH_SAFE (i, next, hmap_node, &installed_flows) {
-        struct ovn_flow *d = ovn_flow_lookup(flow_table, i);
+    HMAP_FOR_EACH_SAFE (i, next, match_hmap_node, &installed_flows) {
+        struct ovn_flow *d = ovn_flow_lookup(&flow_table->match_flow_table,
+                                             i, false);
         if (!d) {
             /* Installed flow is no longer desirable.  Delete it from the
              * switch and from installed_flows. */
@@ -935,9 +1033,13 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
             add_flow_mod(&fm, &msgs);
             ovn_flow_log(i, "removing installed");
 
-            hmap_remove(&installed_flows, &i->hmap_node);
+            hmap_remove(&installed_flows, &i->match_hmap_node);
             ovn_flow_destroy(i);
         } else {
+            if (!uuid_equals(&i->sb_uuid, &d->sb_uuid)) {
+                /* Update installed flow's UUID. */
+                i->sb_uuid = d->sb_uuid;
+            }
             if (!ofpacts_equal(i->ofpacts, i->ofpacts_len,
                                d->ofpacts, d->ofpacts_len)) {
                 /* Update actions in installed flow. */
@@ -954,38 +1056,37 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
 
                 /* Replace 'i''s actions by 'd''s. */
                 free(i->ofpacts);
-                i->ofpacts = d->ofpacts;
+                i->ofpacts = xmemdup(d->ofpacts, d->ofpacts_len);
                 i->ofpacts_len = d->ofpacts_len;
-                d->ofpacts = NULL;
-                d->ofpacts_len = 0;
             }
 
-            hmap_remove(flow_table, &d->hmap_node);
-            ovn_flow_destroy(d);
         }
     }
 
-    /* The previous loop removed from 'flow_table' all of the flows that are
-     * already installed.  Thus, any flows remaining in 'flow_table' need to
-     * be added to the flow table. */
+    /* Iterate through the desired flows and add those that aren't found
+     * in the installed flow table. */
     struct ovn_flow *d;
-    HMAP_FOR_EACH_SAFE (d, next, hmap_node, flow_table) {
-        /* Send flow_mod to add flow. */
-        struct ofputil_flow_mod fm = {
-            .match = d->match,
-            .priority = d->priority,
-            .table_id = d->table_id,
-            .ofpacts = d->ofpacts,
-            .ofpacts_len = d->ofpacts_len,
-            .new_cookie = htonll(d->cookie),
-            .command = OFPFC_ADD,
-        };
-        add_flow_mod(&fm, &msgs);
-        ovn_flow_log(d, "adding installed");
-
-        /* Move 'd' from 'flow_table' to installed_flows. */
-        hmap_remove(flow_table, &d->hmap_node);
-        hmap_insert(&installed_flows, &d->hmap_node, d->hmap_node.hash);
+    HMAP_FOR_EACH (d, match_hmap_node, &flow_table->match_flow_table) {
+        i = ovn_flow_lookup(&installed_flows, d, false);
+        if (!i) {
+            /* Send flow_mod to add flow. */
+            struct ofputil_flow_mod fm = {
+                .match = d->match,
+                .priority = d->priority,
+                .table_id = d->table_id,
+                .ofpacts = d->ofpacts,
+                .ofpacts_len = d->ofpacts_len,
+                .new_cookie = htonll(d->cookie),
+                .command = OFPFC_ADD,
+            };
+            add_flow_mod(&fm, &msgs);
+            ovn_flow_log(d, "adding installed");
+
+            /* Copy 'd' from 'flow_table' to installed_flows. */
+            struct ovn_flow *new_node = ofctrl_dup_flow(d);
+            hmap_insert(&installed_flows, &new_node->match_hmap_node,
+                        new_node->match_hmap_node.hash);
+        }
     }
 
     /* Iterate through the installed groups from previous runs. If they
@@ -1010,11 +1111,11 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
         }
         free(group_string);
         ofputil_uninit_group_mod(&gm);
-        ovn_extend_table_remove(groups, installed);
+        ovn_extend_table_remove_existing(groups, installed);
     }
 
-    /* Move the contents of groups->desired to groups->existing. */
-    ovn_extend_table_move(groups);
+    /* Sync the contents of groups->desired to groups->existing. */
+    ovn_extend_table_sync(groups);
 
     /* Iterate through the installed meters from previous runs. If they
      * are not needed delete them. */
@@ -1037,11 +1138,11 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
             free(error);
         }
         free(meter_string);
-        ovn_extend_table_remove(meters, m_installed);
+        ovn_extend_table_remove_existing(meters, m_installed);
     }
 
-    /* Move the contents of meters->desired to meters->existing. */
-    ovn_extend_table_move(meters);
+    /* Sync the contents of meters->desired to meters->existing. */
+    ovn_extend_table_sync(meters);
 
     if (!ovs_list_is_empty(&msgs)) {
         /* Add a barrier to the list of messages. */
diff --git a/ovn/controller/ofctrl.h b/ovn/controller/ofctrl.h
index 9346f5c..5efbd01 100644
--- a/ovn/controller/ofctrl.h
+++ b/ovn/controller/ofctrl.h
@@ -21,6 +21,7 @@
 
 #include "openvswitch/meta-flow.h"
 #include "ovsdb-idl.h"
+#include "hindex.h"
 
 struct ovn_extend_table;
 struct hmap;
@@ -29,15 +30,24 @@ struct ofpbuf;
 struct ovsrec_bridge;
 struct shash;
 
+struct ovn_desired_flow_table {
+    /* Hash map flow table using flow match conditions as hash key.*/
+    struct hmap match_flow_table;
+
+    /* SB uuid index for the nodes in match_flow_table.*/
+    struct hindex uuid_flow_table;
+};
+
 /* Interface for OVN main loop. */
 void ofctrl_init(struct ovn_extend_table *group_table,
                  struct ovn_extend_table *meter_table);
 void ofctrl_run(const struct ovsrec_bridge *br_int,
                 struct shash *pending_ct_zones);
 enum mf_field_id ofctrl_get_mf_field_id(void);
-bool ofctrl_can_put(void);
-void ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
-                int64_t nb_cfg);
+void ofctrl_put(struct ovn_desired_flow_table *,
+                struct shash *pending_ct_zones,
+                int64_t nb_cfg,
+                bool flow_changed);
 void ofctrl_wait(void);
 void ofctrl_destroy(void);
 int64_t ofctrl_get_cur_cfg(void);
@@ -51,8 +61,15 @@ char *ofctrl_inject_pkt(const struct ovsrec_bridge *br_int,
                         const struct shash *port_groups);
 
 /* Flow table interfaces to the rest of ovn-controller. */
-void ofctrl_add_flow(struct hmap *desired_flows, uint8_t table_id,
+void ofctrl_add_flow(struct ovn_desired_flow_table *, uint8_t table_id,
                      uint16_t priority, uint64_t cookie,
-                     const struct match *, const struct ofpbuf *ofpacts);
+                     const struct match *, const struct ofpbuf *ofpacts,
+                     const struct uuid *);
+
+void ofctrl_remove_flows(struct ovn_desired_flow_table *, const struct uuid *);
+
+void ovn_desired_flow_table_init(struct ovn_desired_flow_table *);
+void ovn_desired_flow_table_clear(struct ovn_desired_flow_table *);
+void ovn_desired_flow_table_destroy(struct ovn_desired_flow_table *);
 
 #endif /* ovn/ofctrl.h */
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index 0a3a803..9d78182 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -795,11 +795,13 @@ en_runtime_data_run(struct engine_node *node)
 
 struct ed_type_flow_output {
     /* desired flows */
-    struct hmap flow_table;
+    struct ovn_desired_flow_table flow_table;
     /* group ids for load balancing */
     struct ovn_extend_table group_table;
     /* meter ids for QoS */
     struct ovn_extend_table meter_table;
+    /* conjunction id offset */
+    uint32_t conj_id_ofs;
 };
 
 static void
@@ -807,9 +809,10 @@ en_flow_output_init(struct engine_node *node)
 {
     struct ed_type_flow_output *data =
         (struct ed_type_flow_output *)node->data;
-    hmap_init(&data->flow_table);
+    ovn_desired_flow_table_init(&data->flow_table);
     ovn_extend_table_init(&data->group_table);
     ovn_extend_table_init(&data->meter_table);
+    data->conj_id_ofs = 1;
 }
 
 static void
@@ -817,7 +820,7 @@ en_flow_output_cleanup(struct engine_node *node)
 {
     struct ed_type_flow_output *data =
         (struct ed_type_flow_output *)node->data;
-    hmap_destroy(&data->flow_table);
+    ovn_desired_flow_table_destroy(&data->flow_table);
     ovn_extend_table_destroy(&data->group_table);
     ovn_extend_table_destroy(&data->meter_table);
 }
@@ -849,22 +852,27 @@ en_flow_output_run(struct engine_node *node)
         engine_ovsdb_node_get_index(
                 engine_get_input("SB_chassis", node),
                 "name");
-    const struct sbrec_chassis *chassis
-        = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id);
+    const struct sbrec_chassis *chassis = NULL;
+    if (chassis_id) {
+        chassis = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id);
+    }
 
     ovs_assert(br_int && chassis);
 
     struct ed_type_flow_output *fo =
         (struct ed_type_flow_output *)node->data;
-    struct hmap *flow_table = &fo->flow_table;
+    struct ovn_desired_flow_table *flow_table = &fo->flow_table;
     struct ovn_extend_table *group_table = &fo->group_table;
     struct ovn_extend_table *meter_table = &fo->meter_table;
+    uint32_t *conj_id_ofs = &fo->conj_id_ofs;
 
     static bool first_run = true;
     if (first_run) {
         first_run = false;
     } else {
-        hmap_clear(flow_table);
+        ovn_desired_flow_table_clear(flow_table);
+        ovn_extend_table_clear(group_table, false /* desired */);
+        ovn_extend_table_clear(meter_table, false /* desired */);
     }
 
     struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath =
@@ -893,6 +901,7 @@ en_flow_output_run(struct engine_node *node)
         (struct sbrec_mac_binding_table *)EN_OVSDB_GET(
             engine_get_input("SB_mac_binding", node));
 
+    *conj_id_ofs = 1;
     lflow_run(sbrec_chassis_by_name,
               sbrec_multicast_group_by_name_datapath,
               sbrec_port_binding_by_name,
@@ -901,7 +910,7 @@ en_flow_output_run(struct engine_node *node)
               mac_binding_table,
               chassis, local_datapaths, addr_sets,
               port_groups, active_tunnels, local_lport_ids,
-              flow_table, group_table, meter_table);
+              flow_table, group_table, meter_table, conj_id_ofs);
 
     enum mf_field_id mff_ovn_geneve = ofctrl_get_mf_field_id();
 
@@ -923,9 +932,84 @@ en_flow_output_run(struct engine_node *node)
         local_datapaths, local_lports,
         active_tunnels,
         flow_table);
+
     node->changed = true;
 }
 
+static bool
+flow_output_sb_logical_flow_handler(struct engine_node *node)
+{
+    struct ed_type_runtime_data *data =
+        (struct ed_type_runtime_data *)engine_get_input(
+                "runtime_data", node)->data;
+    struct hmap *local_datapaths = &data->local_datapaths;
+    struct sset *local_lport_ids = &data->local_lport_ids;
+    struct sset *active_tunnels = &data->active_tunnels;
+    struct shash *addr_sets = &data->addr_sets;
+    struct shash *port_groups = &data->port_groups;
+
+    struct ovsrec_open_vswitch_table *ovs_table =
+        (struct ovsrec_open_vswitch_table *)EN_OVSDB_GET(
+            engine_get_input("OVS_open_vswitch", node));
+    struct ovsrec_bridge_table *bridge_table =
+        (struct ovsrec_bridge_table *)EN_OVSDB_GET(
+            engine_get_input("OVS_bridge", node));
+    const struct ovsrec_bridge *br_int = get_br_int(bridge_table, ovs_table);
+    const char *chassis_id = get_chassis_id(ovs_table);
+
+    struct ovsdb_idl_index *sbrec_chassis_by_name =
+        engine_ovsdb_node_get_index(
+                engine_get_input("SB_chassis", node),
+                "name");
+    const struct sbrec_chassis *chassis = NULL;
+    if (chassis_id) {
+        chassis = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id);
+    }
+
+    ovs_assert(br_int && chassis);
+
+    struct ed_type_flow_output *fo =
+        (struct ed_type_flow_output *)node->data;
+    struct ovn_desired_flow_table *flow_table = &fo->flow_table;
+    struct ovn_extend_table *group_table = &fo->group_table;
+    struct ovn_extend_table *meter_table = &fo->meter_table;
+    uint32_t *conj_id_ofs = &fo->conj_id_ofs;
+
+    struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath =
+        engine_ovsdb_node_get_index(
+                engine_get_input("SB_multicast_group", node),
+                "name_datapath");
+
+    struct ovsdb_idl_index *sbrec_port_binding_by_name =
+        engine_ovsdb_node_get_index(
+                engine_get_input("SB_port_binding", node),
+                "name");
+
+    struct sbrec_dhcp_options_table *dhcp_table =
+        (struct sbrec_dhcp_options_table *)EN_OVSDB_GET(
+            engine_get_input("SB_dhcp_options", node));
+
+    struct sbrec_dhcpv6_options_table *dhcpv6_table =
+        (struct sbrec_dhcpv6_options_table *)EN_OVSDB_GET(
+            engine_get_input("SB_dhcpv6_options", node));
+
+    struct sbrec_logical_flow_table *logical_flow_table =
+        (struct sbrec_logical_flow_table *)EN_OVSDB_GET(
+            engine_get_input("SB_logical_flow", node));
+
+    bool handled = lflow_handle_changed_flows(sbrec_chassis_by_name,
+              sbrec_multicast_group_by_name_datapath,
+              sbrec_port_binding_by_name,
+              dhcp_table, dhcpv6_table,
+              logical_flow_table,
+              local_datapaths, chassis, addr_sets,
+              port_groups, active_tunnels, local_lport_ids,
+              flow_table, group_table, meter_table, conj_id_ofs);
+
+    node->changed = true;
+    return handled;
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -1021,13 +1105,11 @@ main(int argc, char *argv[])
 
     engine_add_input(&en_flow_output, &en_sb_chassis, NULL);
     engine_add_input(&en_flow_output, &en_sb_encap, NULL);
-    engine_add_input(&en_flow_output, &en_sb_address_set, NULL);
-    engine_add_input(&en_flow_output, &en_sb_port_group, NULL);
     engine_add_input(&en_flow_output, &en_sb_multicast_group, NULL);
     engine_add_input(&en_flow_output, &en_sb_datapath_binding, NULL);
     engine_add_input(&en_flow_output, &en_sb_port_binding, NULL);
     engine_add_input(&en_flow_output, &en_sb_mac_binding, NULL);
-    engine_add_input(&en_flow_output, &en_sb_logical_flow, NULL);
+    engine_add_input(&en_flow_output, &en_sb_logical_flow, flow_output_sb_logical_flow_handler);
     engine_add_input(&en_flow_output, &en_sb_dhcp_options, NULL);
     engine_add_input(&en_flow_output, &en_sb_dhcpv6_options, NULL);
     engine_add_input(&en_flow_output, &en_sb_dns, NULL);
@@ -1059,6 +1141,7 @@ main(int argc, char *argv[])
 
     uint64_t engine_run_id = 0;
     uint64_t old_engine_run_id = 0;
+
     /* Main loop. */
     exiting = false;
     while (!exiting) {
@@ -1137,29 +1220,24 @@ main(int argc, char *argv[])
                        sbrec_chassis_table_get(ovnsb_idl_loop.idl),
                        chassis_id);
 
-            if (ofctrl_can_put()) {
-                stopwatch_start(CONTROLLER_LOOP_STOPWATCH_NAME,
-                                time_msec());
-                engine_run(&en_flow_output, ++engine_run_id);
-                stopwatch_stop(CONTROLLER_LOOP_STOPWATCH_NAME,
-                               time_msec());
-
-                if (ovs_idl_txn) {
-                    commit_ct_zones(br_int, &ed_runtime_data.pending_ct_zones);
-                    bfd_run(sbrec_chassis_by_name,
-                            sbrec_port_binding_by_datapath,
-                            ovsrec_interface_table_get(ovs_idl_loop.idl),
-                            br_int, chassis,
-                            &ed_runtime_data.local_datapaths);
-                }
-                if (en_flow_output.changed) {
-                    ofctrl_put(&ed_flow_output.flow_table,
-                               &ed_runtime_data.pending_ct_zones,
-                               get_nb_cfg(sbrec_sb_global_table_get(
-                                              ovnsb_idl_loop.idl)));
-                }
+            stopwatch_start(CONTROLLER_LOOP_STOPWATCH_NAME,
+                            time_msec());
+            engine_run(&en_flow_output, ++engine_run_id);
+            stopwatch_stop(CONTROLLER_LOOP_STOPWATCH_NAME,
+                           time_msec());
+            if (ovs_idl_txn) {
+                commit_ct_zones(br_int, &ed_runtime_data.pending_ct_zones);
+                bfd_run(sbrec_chassis_by_name,
+                        sbrec_port_binding_by_datapath,
+                        ovsrec_interface_table_get(ovs_idl_loop.idl),
+                        br_int, chassis,
+                        &ed_runtime_data.local_datapaths);
             }
-
+            ofctrl_put(&ed_flow_output.flow_table,
+                       &ed_runtime_data.pending_ct_zones,
+                       get_nb_cfg(sbrec_sb_global_table_get(
+                                      ovnsb_idl_loop.idl)),
+                       en_flow_output.changed);
             pinctrl_run(ovnsb_idl_txn, sbrec_chassis_by_name,
                         sbrec_datapath_binding_by_key,
                         sbrec_port_binding_by_datapath,
@@ -1171,9 +1249,11 @@ main(int argc, char *argv[])
                         &ed_runtime_data.local_datapaths,
                         &ed_runtime_data.active_tunnels);
 
-            update_sb_monitors(ovnsb_idl_loop.idl, chassis,
-                               &ed_runtime_data.local_lports,
-                               &ed_runtime_data.local_datapaths);
+            if (en_runtime_data.changed) {
+                update_sb_monitors(ovnsb_idl_loop.idl, chassis,
+                                   &ed_runtime_data.local_lports,
+                                   &ed_runtime_data.local_datapaths);
+            }
 
         }
         if (old_engine_run_id == engine_run_id) {
diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
index 5faf97e..34434a7 100644
--- a/ovn/controller/physical.c
+++ b/ovn/controller/physical.c
@@ -44,6 +44,9 @@
 
 VLOG_DEFINE_THIS_MODULE(physical);
 
+/* UUID to identify OF flows not associated with ovsdb rows. */
+static struct uuid *hc_uuid = NULL;
+
 void
 physical_register_ovs_idl(struct ovsdb_idl *ovs_idl)
 {
@@ -188,9 +191,10 @@ get_zone_ids(const struct sbrec_port_binding *binding,
 }
 
 static void
-put_local_common_flows(uint32_t dp_key, uint32_t port_key,
+put_local_common_flows(struct ovn_desired_flow_table *flow_table,
+                       uint32_t dp_key, uint32_t port_key,
                        bool nested_container, const struct zone_ids *zone_ids,
-                       struct ofpbuf *ofpacts_p, struct hmap *flow_table)
+                       struct ofpbuf *ofpacts_p)
 {
     struct match match;
 
@@ -224,7 +228,7 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key,
     /* Resubmit to table 34. */
     put_resubmit(OFTABLE_CHECK_LOOPBACK, ofpacts_p);
     ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100, 0,
-                    &match, ofpacts_p);
+                    &match, ofpacts_p, hc_uuid);
 
     /* Table 34, Priority 100.
      * =======================
@@ -239,7 +243,7 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key,
     match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, port_key);
     match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
     ofctrl_add_flow(flow_table, OFTABLE_CHECK_LOOPBACK, 100, 0,
-                    &match, ofpacts_p);
+                    &match, ofpacts_p, hc_uuid);
 
     /* Table 64, Priority 100.
      * =======================
@@ -263,7 +267,7 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key,
     put_resubmit(OFTABLE_LOG_TO_PHY, ofpacts_p);
     put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p));
     ofctrl_add_flow(flow_table, OFTABLE_SAVE_INPORT, 100, 0,
-                    &match, ofpacts_p);
+                    &match, ofpacts_p, hc_uuid);
 }
 
 static void
@@ -299,8 +303,8 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
                       const struct hmap *local_datapaths,
                       const struct sbrec_port_binding *binding,
                       const struct sbrec_chassis *chassis,
-                      struct ofpbuf *ofpacts_p,
-                      struct hmap *flow_table)
+                      struct ovn_desired_flow_table *flow_table,
+                      struct ofpbuf *ofpacts_p)
 {
     uint32_t dp_key = binding->datapath->tunnel_key;
     uint32_t port_key = binding->tunnel_key;
@@ -328,8 +332,8 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
         }
 
         struct zone_ids binding_zones = get_zone_ids(binding, ct_zones);
-        put_local_common_flows(dp_key, port_key, false, &binding_zones,
-                               ofpacts_p, flow_table);
+        put_local_common_flows(flow_table, dp_key, port_key, false,
+                               &binding_zones, ofpacts_p);
 
         match_init_catchall(&match);
         ofpbuf_clear(ofpacts_p);
@@ -356,7 +360,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
         ofpact_finish_CLONE(ofpacts_p, &clone);
 
         ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 100, 0,
-                        &match, ofpacts_p);
+                        &match, ofpacts_p, hc_uuid);
         return;
     }
 
@@ -425,7 +429,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
         }
 
         ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100, 0,
-                        &match, ofpacts_p);
+                        &match, ofpacts_p, hc_uuid);
 
         goto out;
     }
@@ -523,8 +527,8 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
          */
 
         struct zone_ids zone_ids = get_zone_ids(binding, ct_zones);
-        put_local_common_flows(dp_key, port_key, nested_container, &zone_ids,
-                               ofpacts_p, flow_table);
+        put_local_common_flows(flow_table, dp_key, port_key, nested_container,
+                               &zone_ids, ofpacts_p);
 
         /* Table 0, Priority 150 and 100.
          * ==============================
@@ -568,7 +572,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
         /* Resubmit to first logical ingress pipeline table. */
         put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, ofpacts_p);
         ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG,
-                        tag ? 150 : 100, 0, &match, ofpacts_p);
+                        tag ? 150 : 100, 0, &match, ofpacts_p, hc_uuid);
 
         if (!tag && (!strcmp(binding->type, "localnet")
                      || !strcmp(binding->type, "l2gateway"))) {
@@ -578,7 +582,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
              * action. */
             ofpbuf_pull(ofpacts_p, ofpacts_orig_size);
             match_set_dl_tci_masked(&match, 0, htons(VLAN_CFI));
-            ofctrl_add_flow(flow_table, 0, 100, 0, &match, ofpacts_p);
+            ofctrl_add_flow(flow_table, 0, 100, 0, &match, ofpacts_p, hc_uuid);
         }
 
         /* Table 65, Priority 100.
@@ -606,7 +610,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
             ofpact_put_STRIP_VLAN(ofpacts_p);
         }
         ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 100, 0,
-                        &match, ofpacts_p);
+                        &match, ofpacts_p, hc_uuid);
     } else if (!tun && !is_ha_remote) {
         /* Remote port connected by localnet port */
         /* Table 33, priority 100.
@@ -629,7 +633,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
         /* Resubmit to table 33. */
         put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_p);
         ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100, 0,
-                        &match, ofpacts_p);
+                        &match, ofpacts_p, hc_uuid);
     } else {
         /* Remote port connected by tunnel */
 
@@ -720,7 +724,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
             ofpact_finish_BUNDLE(ofpacts_p, &bundle);
         }
         ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 100, 0,
-                        &match, ofpacts_p);
+                        &match, ofpacts_p, hc_uuid);
     }
 out:
     if (gateway_chassis) {
@@ -736,7 +740,7 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve,
                   const struct sbrec_multicast_group *mc,
                   struct ofpbuf *ofpacts_p,
                   struct ofpbuf *remote_ofpacts_p,
-                  struct hmap *flow_table)
+                  struct ovn_desired_flow_table *flow_table)
 {
     uint32_t dp_key = mc->datapath->tunnel_key;
     if (!get_local_datapath(local_datapaths, dp_key)) {
@@ -812,7 +816,7 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve,
         put_load(mc->tunnel_key, MFF_LOG_OUTPORT, 0, 32, ofpacts_p);
 
         ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100, 0,
-                        &match, ofpacts_p);
+                        &match, ofpacts_p, hc_uuid);
     }
 
     /* Table 32, priority 100.
@@ -850,7 +854,7 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve,
                 put_resubmit(OFTABLE_LOCAL_OUTPUT, remote_ofpacts_p);
             }
             ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 100, 0,
-                            &match, remote_ofpacts_p);
+                            &match, remote_ofpacts_p, hc_uuid);
         }
     }
     sset_destroy(&remote_chassis);
@@ -879,8 +883,13 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
              const struct hmap *local_datapaths,
              const struct sset *local_lports,
              const struct sset *active_tunnels,
-             struct hmap *flow_table)
+             struct ovn_desired_flow_table *flow_table)
 {
+    if (!hc_uuid) {
+        hc_uuid = xmalloc(sizeof(struct uuid));
+        uuid_generate(hc_uuid);
+    }
+
     /* This bool tracks physical mapping changes. */
     bool physical_map_changed = false;
 
@@ -1004,7 +1013,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
                               mff_ovn_geneve, ct_zones,
                               active_tunnels,
                               local_datapaths, binding, chassis,
-                              &ofpacts, flow_table);
+                              flow_table, &ofpacts);
     }
 
     /* Handle output to multicast groups, in tables 32 and 33. */
@@ -1054,7 +1063,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
         put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
 
         ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 100, 0, &match,
-                        &ofpacts);
+                        &ofpacts, hc_uuid);
     }
 
     /* Add flows for VXLAN encapsulations.  Due to the limited amount of
@@ -1087,7 +1096,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
             put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, &ofpacts);
 
             ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 100, 0, &match,
-                            &ofpacts);
+                            &ofpacts, hc_uuid);
         }
     }
 
@@ -1108,7 +1117,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
     ofpbuf_clear(&ofpacts);
     put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
     ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
-                    &match, &ofpacts);
+                    &match, &ofpacts, hc_uuid);
 
     /* Table 32, priority 150.
      * =======================
@@ -1122,7 +1131,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
     ofpbuf_clear(&ofpacts);
     put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
     ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
-                    &match, &ofpacts);
+                    &match, &ofpacts, hc_uuid);
 
     /* Table 32, priority 150.
      * =======================
@@ -1145,7 +1154,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
             match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, pb->tunnel_key);
             match_set_metadata(&match, htonll(pb->datapath->tunnel_key));
             ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
-                            &match, &ofpacts);
+                            &match, &ofpacts, hc_uuid);
         }
     }
 
@@ -1157,7 +1166,8 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
     match_init_catchall(&match);
     ofpbuf_clear(&ofpacts);
     put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
-    ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 0, 0, &match, &ofpacts);
+    ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 0, 0, &match, &ofpacts,
+                    hc_uuid);
 
     /* Table 34, Priority 0.
      * =======================
@@ -1172,7 +1182,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
     }
     put_resubmit(OFTABLE_LOG_EGRESS_PIPELINE, &ofpacts);
     ofctrl_add_flow(flow_table, OFTABLE_CHECK_LOOPBACK, 0, 0, &match,
-                    &ofpacts);
+                    &ofpacts, hc_uuid);
 
     /* Table 64, Priority 0.
      * =======================
@@ -1182,7 +1192,8 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
     match_init_catchall(&match);
     ofpbuf_clear(&ofpacts);
     put_resubmit(OFTABLE_LOG_TO_PHY, &ofpacts);
-    ofctrl_add_flow(flow_table, OFTABLE_SAVE_INPORT, 0, 0, &match, &ofpacts);
+    ofctrl_add_flow(flow_table, OFTABLE_SAVE_INPORT, 0, 0, &match, &ofpacts,
+                    hc_uuid);
 
     ofpbuf_uninit(&ofpacts);
 
diff --git a/ovn/controller/physical.h b/ovn/controller/physical.h
index a7a4def..1dd2b9d 100644
--- a/ovn/controller/physical.h
+++ b/ovn/controller/physical.h
@@ -54,6 +54,6 @@ void physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
                   const struct hmap *local_datapaths,
                   const struct sset *local_lports,
                   const struct sset *active_tunnels,
-                  struct hmap *flow_table);
+                  struct ovn_desired_flow_table *);
 
 #endif /* ovn/physical.h */
diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c
index 5c559e3..53fe9ff 100644
--- a/ovn/lib/actions.c
+++ b/ovn/lib/actions.c
@@ -1049,7 +1049,8 @@ encode_CT_LB(const struct ovnact_ct_lb *cl,
                       recirc_table, zone_reg);
     }
 
-    table_id = ovn_extend_table_assign_id(ep->group_table, &ds);
+    table_id = ovn_extend_table_assign_id(ep->group_table, &ds,
+                                          ep->lflow_uuid);
     ds_destroy(&ds);
     if (table_id == EXT_TABLE_ID_INVALID) {
         return;
@@ -2228,7 +2229,8 @@ encode_SET_METER(const struct ovnact_set_meter *cl,
                       cl->rate);
     }
 
-    table_id = ovn_extend_table_assign_id(ep->meter_table, &ds);
+    table_id = ovn_extend_table_assign_id(ep->meter_table, &ds,
+                                          ep->lflow_uuid);
     if (table_id == EXT_TABLE_ID_INVALID) {
         ds_destroy(&ds);
         return;
diff --git a/ovn/lib/extend-table.c b/ovn/lib/extend-table.c
index e18713b..e4dd52a 100644
--- a/ovn/lib/extend-table.c
+++ b/ovn/lib/extend-table.c
@@ -17,6 +17,7 @@
 #include <config.h>
 #include "bitmap.h"
 #include "hash.h"
+#include "lib/uuid.h"
 #include "openvswitch/vlog.h"
 #include "ovn/lib/extend-table.h"
 
@@ -89,9 +90,10 @@ ovn_extend_table_clear(struct ovn_extend_table *table, bool existing)
     }
 }
 
+/* Remove an entry from existing table */
 void
-ovn_extend_table_remove(struct ovn_extend_table *table,
-                        struct ovn_extend_table_info *existing)
+ovn_extend_table_remove_existing(struct ovn_extend_table *table,
+                                 struct ovn_extend_table_info *existing)
 {
     /* Remove 'existing' from 'groups->existing' */
     hmap_remove(&table->existing, &existing->hmap_node);
@@ -102,21 +104,50 @@ ovn_extend_table_remove(struct ovn_extend_table *table,
     free(existing);
 }
 
+/* Remove entries in desired table that are created by the lflow_uuid */
 void
-ovn_extend_table_move(struct ovn_extend_table *table)
+ovn_extend_table_remove_desired(struct ovn_extend_table *table,
+                                const struct uuid *lflow_uuid)
+{
+    struct ovn_extend_table_info *e, *next_e;
+    HMAP_FOR_EACH_SAFE (e, next_e, hmap_node, &table->desired) {
+        if (uuid_equals(&e->lflow_uuid, lflow_uuid)) {
+            hmap_remove(&table->desired, &e->hmap_node);
+            ds_destroy(&e->info);
+            if (e->new_table_id) {
+                bitmap_set0(table->table_ids, e->table_id);
+            }
+            free(e);
+        }
+    }
+
+}
+
+static struct ovn_extend_table_info*
+ovn_extend_info_clone(struct ovn_extend_table_info *source)
+{
+    struct ovn_extend_table_info *clone = xmalloc(sizeof *clone);
+    ds_clone(&clone->info, &source->info);
+    clone->table_id = source->table_id;
+    clone->new_table_id = source->new_table_id;
+    clone->hmap_node.hash = source->hmap_node.hash;
+    clone->lflow_uuid = source->lflow_uuid;
+    return clone;
+}
+
+void
+ovn_extend_table_sync(struct ovn_extend_table *table)
 {
     struct ovn_extend_table_info *desired, *next;
 
-    /* Move the contents of desired to existing. */
+    /* Copy the contents of desired to existing. */
     HMAP_FOR_EACH_SAFE (desired, next, hmap_node, &table->desired) {
-        hmap_remove(&table->desired, &desired->hmap_node);
-
         if (!ovn_extend_table_lookup(&table->existing, desired)) {
-            hmap_insert(&table->existing, &desired->hmap_node,
-                        desired->hmap_node.hash);
-        } else {
-           ds_destroy(&desired->info);
-           free(desired);
+            desired->new_table_id = false;
+            struct ovn_extend_table_info *clone =
+                ovn_extend_info_clone(desired);
+            hmap_insert(&table->existing, &clone->hmap_node,
+                        clone->hmap_node.hash);
         }
     }
 }
@@ -124,7 +155,8 @@ ovn_extend_table_move(struct ovn_extend_table *table)
 /* Assign a new table ID for the table information from the bitmap.
  * If it already exists, return the old ID. */
 uint32_t
-ovn_extend_table_assign_id(struct ovn_extend_table *table, struct ds *ds)
+ovn_extend_table_assign_id(struct ovn_extend_table *table, struct ds *ds,
+                           struct uuid lflow_uuid)
 {
     uint32_t table_id = 0, hash;
     struct ovn_extend_table_info *table_info;
@@ -133,7 +165,8 @@ ovn_extend_table_assign_id(struct ovn_extend_table *table, struct ds *ds)
 
     /* Check whether we have non installed but allocated group_id. */
     HMAP_FOR_EACH_WITH_HASH (table_info, hmap_node, hash, &table->desired) {
-        if (!strcmp(ds_cstr(&table_info->info), ds_cstr(ds))) {
+        if (!strcmp(ds_cstr(&table_info->info), ds_cstr(ds)) &&
+            table_info->new_table_id) {
             return table_info->table_id;
         }
     }
@@ -165,6 +198,7 @@ ovn_extend_table_assign_id(struct ovn_extend_table *table, struct ds *ds)
     table_info->table_id = table_id;
     table_info->hmap_node.hash = hash;
     table_info->new_table_id = new_table_id;
+    table_info->lflow_uuid = lflow_uuid;
 
     hmap_insert(&table->desired,
                 &table_info->hmap_node, table_info->hmap_node.hash);
diff --git a/ovn/lib/extend-table.h b/ovn/lib/extend-table.h
index d9ae549..7473d4a 100644
--- a/ovn/lib/extend-table.h
+++ b/ovn/lib/extend-table.h
@@ -23,6 +23,7 @@
 #include "openvswitch/dynamic-string.h"
 #include "openvswitch/hmap.h"
 #include "openvswitch/list.h"
+#include "openvswitch/uuid.h"
 
 /* Used to manage expansion tables associated with Flow table,
  * such as the Group Table or Meter Table. */
@@ -37,6 +38,7 @@ struct ovn_extend_table {
 struct ovn_extend_table_info {
     struct hmap_node hmap_node;
     struct ds info;     /* Details string for the table entity. */
+    struct uuid lflow_uuid;
     uint32_t table_id;
     bool new_table_id;  /* 'True' if 'table_id' was reserved from
                          * ovn_extend_table's 'table_ids' bitmap. */
@@ -51,14 +53,18 @@ struct ovn_extend_table_info *ovn_extend_table_lookup(
 
 void ovn_extend_table_clear(struct ovn_extend_table *, bool);
 
-void ovn_extend_table_remove(struct ovn_extend_table *,
-                             struct ovn_extend_table_info *);
+void ovn_extend_table_remove_existing(struct ovn_extend_table *,
+                                      struct ovn_extend_table_info *);
 
-/* Move the contents of desired to existing. */
-void ovn_extend_table_move(struct ovn_extend_table *);
+void ovn_extend_table_remove_desired(struct ovn_extend_table *,
+                                     const struct uuid *lflow_uuid);
+
+/* Copy the contents of desired to existing. */
+void ovn_extend_table_sync(struct ovn_extend_table *);
 
 uint32_t ovn_extend_table_assign_id(struct ovn_extend_table *,
-                                    struct ds *);
+                                    struct ds *,
+                                    struct uuid lflow_uuid);
 
 /* Iterates 'DESIRED' through all of the 'ovn_extend_table_info's in
  * 'TABLE'->desired that are not in 'TABLE'->existing.  (The loop body
