diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
index bb76608..f76e692 100644
--- a/ovn/controller/binding.c
+++ b/ovn/controller/binding.c
@@ -106,8 +106,8 @@ get_local_iface_ids(const struct ovsrec_bridge *br_int,
 }
 
 static void
-add_local_datapath__(const struct ldatapath_index *ldatapaths,
-                     const struct lport_index *lports,
+add_local_datapath__(struct controller_ctx *ctx,
+                     const struct ldatapath_index *ldatapaths,
                      const struct sbrec_datapath_binding *datapath,
                      bool has_local_l3gateway, int depth,
                      struct hmap *local_datapaths)
@@ -143,9 +143,9 @@ add_local_datapath__(const struct ldatapath_index *ldatapaths,
             const char *peer_name = smap_get(&pb->options, "peer");
             if (peer_name) {
                 const struct sbrec_port_binding *peer = lport_lookup_by_name(
-                    lports, peer_name);
+                    ctx->ovnsb_idl, peer_name);
                 if (peer && peer->datapath) {
-                    add_local_datapath__(ldatapaths, lports, peer->datapath,
+                    add_local_datapath__(ctx, ldatapaths, peer->datapath,
                                          false, depth + 1, local_datapaths);
                 }
             }
@@ -154,12 +154,12 @@ add_local_datapath__(const struct ldatapath_index *ldatapaths,
 }
 
 static void
-add_local_datapath(const struct ldatapath_index *ldatapaths,
-                   const struct lport_index *lports,
+add_local_datapath(struct controller_ctx *ctx,
+                   const struct ldatapath_index *ldatapaths,
                    const struct sbrec_datapath_binding *datapath,
                    bool has_local_l3gateway, struct hmap *local_datapaths)
 {
-    add_local_datapath__(ldatapaths, lports, datapath, has_local_l3gateway, 0,
+    add_local_datapath__(ctx, ldatapaths, datapath, has_local_l3gateway, 0,
                          local_datapaths);
 }
 
@@ -356,7 +356,6 @@ setup_qos(const char *egress_iface, struct hmap *queue_map)
 static void
 consider_local_datapath(struct controller_ctx *ctx,
                         const struct ldatapath_index *ldatapaths,
-                        const struct lport_index *lports,
                         const struct sbrec_chassis *chassis_rec,
                         const struct sbrec_port_binding *binding_rec,
                         struct hmap *qos_map,
@@ -375,7 +374,7 @@ consider_local_datapath(struct controller_ctx *ctx,
             /* Add child logical port to the set of all local ports. */
             sset_add(local_lports, binding_rec->logical_port);
         }
-        add_local_datapath(ldatapaths, lports, binding_rec->datapath,
+        add_local_datapath(ctx, ldatapaths, binding_rec->datapath,
                            false, local_datapaths);
         if (iface_rec && qos_map && ctx->ovs_idl_txn) {
             get_qos_params(binding_rec, qos_map);
@@ -390,7 +389,7 @@ consider_local_datapath(struct controller_ctx *ctx,
         our_chassis = chassis_id && !strcmp(chassis_id, chassis_rec->name);
         if (our_chassis) {
             sset_add(local_lports, binding_rec->logical_port);
-            add_local_datapath(ldatapaths, lports, binding_rec->datapath,
+            add_local_datapath(ctx, ldatapaths, binding_rec->datapath,
                                false, local_datapaths);
         }
     } else if (!strcmp(binding_rec->type, "chassisredirect")) {
@@ -398,7 +397,7 @@ consider_local_datapath(struct controller_ctx *ctx,
                                           "redirect-chassis");
         our_chassis = chassis_id && !strcmp(chassis_id, chassis_rec->name);
         if (our_chassis) {
-            add_local_datapath(ldatapaths, lports, binding_rec->datapath,
+            add_local_datapath(ctx, ldatapaths, binding_rec->datapath,
                                false, local_datapaths);
         }
     } else if (!strcmp(binding_rec->type, "l3gateway")) {
@@ -406,7 +405,7 @@ consider_local_datapath(struct controller_ctx *ctx,
                                           "l3gateway-chassis");
         our_chassis = chassis_id && !strcmp(chassis_id, chassis_rec->name);
         if (our_chassis) {
-            add_local_datapath(ldatapaths, lports, binding_rec->datapath,
+            add_local_datapath(ctx, ldatapaths, binding_rec->datapath,
                                true, local_datapaths);
         }
     } else if (!strcmp(binding_rec->type, "localnet")) {
@@ -446,7 +445,7 @@ void
 binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
             const struct sbrec_chassis *chassis_rec,
             const struct ldatapath_index *ldatapaths,
-            const struct lport_index *lports, struct hmap *local_datapaths,
+            struct hmap *local_datapaths,
             struct sset *local_lports)
 {
     if (!chassis_rec) {
@@ -468,7 +467,7 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
      * chassis and update the binding accordingly.  This includes both
      * directly connected logical ports and children of those ports. */
     SBREC_PORT_BINDING_FOR_EACH(binding_rec, ctx->ovnsb_idl) {
-        consider_local_datapath(ctx, ldatapaths, lports,
+        consider_local_datapath(ctx, ldatapaths,
                                 chassis_rec, binding_rec,
                                 sset_is_empty(&egress_ifaces) ? NULL :
                                 &qos_map, local_datapaths, &lport_to_iface,
diff --git a/ovn/controller/binding.h b/ovn/controller/binding.h
index 3bfa7d1..26ca5ab 100644
--- a/ovn/controller/binding.h
+++ b/ovn/controller/binding.h
@@ -22,7 +22,6 @@
 struct controller_ctx;
 struct hmap;
 struct ldatapath_index;
-struct lport_index;
 struct ovsdb_idl;
 struct ovsrec_bridge;
 struct sbrec_chassis;
@@ -31,7 +30,7 @@ struct sset;
 void binding_register_ovs_idl(struct ovsdb_idl *);
 void binding_run(struct controller_ctx *, const struct ovsrec_bridge *br_int,
                  const struct sbrec_chassis *, const struct ldatapath_index *,
-                 const struct lport_index *, struct hmap *local_datapaths,
+                 struct hmap *local_datapaths,
                  struct sset *all_lports);
 bool binding_cleanup(struct controller_ctx *, const struct sbrec_chassis *);
 
diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c
index 56a7c02..27338ce 100644
--- a/ovn/controller/lflow.c
+++ b/ovn/controller/lflow.c
@@ -46,17 +46,15 @@ lflow_init(void)
 
 struct lookup_port_aux {
     struct ovsdb_idl *ovnsb_idl;
-    const struct lport_index *lports;
     const struct sbrec_datapath_binding *dp;
 };
 
 struct condition_aux {
-    const struct lport_index *lports;
+    struct ovsdb_idl *ovnsb_idl;
     const struct sbrec_chassis *chassis;
 };
 
 static void consider_logical_flow(struct controller_ctx *ctx,
-                                  const struct lport_index *lports,
                                   const struct sbrec_logical_flow *lflow,
                                   const struct hmap *local_datapaths,
                                   struct group_table *group_table,
@@ -73,7 +71,7 @@ lookup_port_cb(const void *aux_, const char *port_name, unsigned int *portp)
     const struct lookup_port_aux *aux = aux_;
 
     const struct sbrec_port_binding *pb
-        = lport_lookup_by_name(aux->lports, port_name);
+        = lport_lookup_by_name(aux->ovnsb_idl, port_name);
     if (pb && pb->datapath == aux->dp) {
         *portp = pb->tunnel_key;
         return true;
@@ -95,7 +93,7 @@ is_chassis_resident_cb(const void *c_aux_, const char *port_name)
     const struct condition_aux *c_aux = c_aux_;
 
     const struct sbrec_port_binding *pb
-        = lport_lookup_by_name(c_aux->lports, port_name);
+        = lport_lookup_by_name(c_aux->ovnsb_idl, port_name);
     return pb && pb->chassis && pb->chassis == c_aux->chassis;
 }
 
@@ -117,7 +115,7 @@ is_gateway_router(const struct sbrec_datapath_binding *ldp,
 
 /* Adds the logical flows from the Logical_Flow table to flow tables. */
 static void
-add_logical_flows(struct controller_ctx *ctx, const struct lport_index *lports,
+add_logical_flows(struct controller_ctx *ctx,
                   const struct hmap *local_datapaths,
                   struct group_table *group_table,
                   const struct sbrec_chassis *chassis,
@@ -143,7 +141,7 @@ add_logical_flows(struct controller_ctx *ctx, const struct lport_index *lports,
     }
 
     SBREC_LOGICAL_FLOW_FOR_EACH (lflow, ctx->ovnsb_idl) {
-        consider_logical_flow(ctx, lports, lflow, local_datapaths,
+        consider_logical_flow(ctx, lflow, local_datapaths,
                               group_table, chassis,
                               &dhcp_opts, &dhcpv6_opts, &conj_id_ofs,
                               addr_sets, flow_table);
@@ -155,7 +153,6 @@ add_logical_flows(struct controller_ctx *ctx, const struct lport_index *lports,
 
 static void
 consider_logical_flow(struct controller_ctx *ctx,
-                      const struct lport_index *lports,
                       const struct sbrec_logical_flow *lflow,
                       const struct hmap *local_datapaths,
                       struct group_table *group_table,
@@ -218,7 +215,6 @@ consider_logical_flow(struct controller_ctx *ctx,
     uint64_t ofpacts_stub[1024 / 8];
     struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
     struct lookup_port_aux aux = {
-        .lports = lports,
         .ovnsb_idl = ctx->ovnsb_idl,
         .dp = lflow->logical_datapath
     };
@@ -261,7 +257,7 @@ consider_logical_flow(struct controller_ctx *ctx,
         return;
     }
 
-    struct condition_aux cond_aux = { lports, chassis };
+    struct condition_aux cond_aux = { ctx->ovnsb_idl, chassis };
     expr = expr_simplify(expr, is_chassis_resident_cb, &cond_aux);
     expr = expr_normalize(expr);
     uint32_t n_conjs = expr_to_matches(expr, lookup_port_cb, &aux,
@@ -318,12 +314,12 @@ put_load(const uint8_t *data, size_t len,
 }
 
 static void
-consider_neighbor_flow(const struct lport_index *lports,
+consider_neighbor_flow(struct controller_ctx *ctx,
                        const struct sbrec_mac_binding *b,
                        struct hmap *flow_table)
 {
     const struct sbrec_port_binding *pb
-        = lport_lookup_by_name(lports, b->logical_port);
+        = lport_lookup_by_name(ctx->ovnsb_idl, b->logical_port);
     if (!pb) {
         return;
     }
@@ -367,16 +363,14 @@ consider_neighbor_flow(const struct lport_index *lports,
 }
 
 /* Adds an OpenFlow flow to flow tables for each MAC binding in the OVN
- * southbound database, using 'lports' to resolve logical port names to
- * numbers. */
+ * southbound database. */
 static void
 add_neighbor_flows(struct controller_ctx *ctx,
-                   const struct lport_index *lports,
                    struct hmap *flow_table)
 {
     const struct sbrec_mac_binding *b;
     SBREC_MAC_BINDING_FOR_EACH (b, ctx->ovnsb_idl) {
-        consider_neighbor_flow(lports, b, flow_table);
+        consider_neighbor_flow(ctx, b, flow_table);
     }
 }
 
@@ -385,15 +379,14 @@ add_neighbor_flows(struct controller_ctx *ctx,
 void
 lflow_run(struct controller_ctx *ctx,
           const struct sbrec_chassis *chassis,
-          const struct lport_index *lports,
           const struct hmap *local_datapaths,
           struct group_table *group_table,
           const struct shash *addr_sets,
           struct hmap *flow_table)
 {
-    add_logical_flows(ctx, lports, local_datapaths, group_table,
+    add_logical_flows(ctx, local_datapaths, group_table,
                       chassis, addr_sets, flow_table);
-    add_neighbor_flows(ctx, lports, flow_table);
+    add_neighbor_flows(ctx, flow_table);
 }
 
 void
diff --git a/ovn/controller/lflow.h b/ovn/controller/lflow.h
index 60d86cd..a2ea042 100644
--- a/ovn/controller/lflow.h
+++ b/ovn/controller/lflow.h
@@ -38,7 +38,6 @@
 struct controller_ctx;
 struct group_table;
 struct hmap;
-struct lport_index;
 struct sbrec_chassis;
 struct simap;
 struct uuid;
@@ -63,7 +62,6 @@ struct uuid;
 void lflow_init(void);
 void lflow_run(struct controller_ctx *,
                const struct sbrec_chassis *chassis,
-               const struct lport_index *,
                const struct hmap *local_datapaths,
                struct group_table *group_table,
                const struct shash *addr_sets,
diff --git a/ovn/controller/lport.c b/ovn/controller/lport.c
index 07173a9..aed6389 100644
--- a/ovn/controller/lport.c
+++ b/ovn/controller/lport.c
@@ -22,6 +22,9 @@
 
 VLOG_DEFINE_THIS_MODULE(lport);
 
+static struct ovsdb_idl_index_cursor lport_by_name_cursor;
+static struct ovsdb_idl_index_cursor lport_by_key_cursor;
+static struct ovsdb_idl_index_cursor dpath_by_key_cursor;
 static struct ovsdb_idl_index_cursor mc_grp_by_dp_name_cursor;
 
 static struct ldatapath *ldatapath_lookup_by_key__(
@@ -86,97 +89,88 @@ const struct ldatapath *ldatapath_lookup_by_key(
     return ldatapath_lookup_by_key__(ldatapaths, dp_key);
 }
 
-/* A logical port. */
-struct lport {
-    struct hmap_node name_node; /* Index by name. */
-    struct hmap_node key_node;  /* Index by (dp_key, port_key). */
-    const struct sbrec_port_binding *pb;
-};
 
-void
-lport_index_init(struct lport_index *lports, struct ovsdb_idl *ovnsb_idl)
+/* Finds and returns the port binding record with the given 'name',
+ * or NULL if no such port binding exists. */
+const struct sbrec_port_binding *
+lport_lookup_by_name(struct ovsdb_idl *idl, const char *name)
 {
-    hmap_init(&lports->by_name);
-    hmap_init(&lports->by_key);
+    struct sbrec_port_binding *value;
+    const struct sbrec_port_binding *pb, *retval =  NULL;
 
-    const struct sbrec_port_binding *pb;
-    SBREC_PORT_BINDING_FOR_EACH (pb, ovnsb_idl) {
-        if (!pb->datapath) {
-            continue;
-        }
+    /* Build key for an indexed lookup. */
+    value = sbrec_port_binding_index_init_row(idl, &sbrec_table_port_binding);
+    sbrec_port_binding_index_set_logical_port(value, xstrdup(name));
+
+    /* Find an entry with matching logical port name. Since this column is
+     * declared to be an index in the OVN_Southbound schema, the first match
+     * (if any) will be the only match. */
+    SBREC_PORT_BINDING_FOR_EACH_EQUAL (pb, &lport_by_name_cursor, value) {
+        retval = pb;
+        break;
+    }
 
-        if (lport_lookup_by_name(lports, pb->logical_port)) {
-            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
-            VLOG_WARN_RL(&rl, "duplicate logical port name '%s'",
-                         pb->logical_port);
-            continue;
-        }
-        if (lport_lookup_by_key(lports, pb->datapath->tunnel_key,
-                                pb->tunnel_key)) {
-            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
-            VLOG_WARN_RL(&rl, "duplicate logical port %"PRId64" in logical "
-                         "datapath %"PRId64,
-                         pb->tunnel_key, pb->datapath->tunnel_key);
-            continue;
-        }
+    sbrec_port_binding_index_destroy_row(value);
 
-        struct lport *p = xmalloc(sizeof *p);
-        hmap_insert(&lports->by_name, &p->name_node,
-                    hash_string(pb->logical_port, 0));
-        hmap_insert(&lports->by_key, &p->key_node,
-                    hash_int(pb->tunnel_key, pb->datapath->tunnel_key));
-        p->pb = pb;
-    }
+    return retval;
 }
 
-void
-lport_index_destroy(struct lport_index *lports)
+/* Finds and returns the datapath binding record with tunnel_key equal to the
+ * given 'dp_key', or NULL if no such datapath binding exists. */
+static const struct sbrec_datapath_binding *
+datapath_lookup_by_key(struct ovsdb_idl *idl, uint64_t dp_key)
 {
-    if (!lports) {
-        return;
-    }
+    struct sbrec_datapath_binding *dbval;
+    const struct sbrec_datapath_binding *db, *retval = NULL;
 
-    /* Destroy all of the "struct lport"s.
-     *
-     * We don't have to remove the node from both indexes. */
-    struct lport *port, *next;
-    HMAP_FOR_EACH_SAFE (port, next, name_node, &lports->by_name) {
-        hmap_remove(&lports->by_name, &port->name_node);
-        free(port);
+    /* Build key for an indexed lookup. */
+    dbval = sbrec_datapath_binding_index_init_row(idl,
+                                                &sbrec_table_datapath_binding);
+    sbrec_datapath_binding_index_set_tunnel_key(dbval, dp_key);
+
+    /* Find an entry with matching tunnel_key. Since this column is declared
+     * to be an index in the OVN_Southbound schema, the first match (if any)
+     * will be the only match. */
+    SBREC_DATAPATH_BINDING_FOR_EACH_EQUAL (db, &dpath_by_key_cursor, dbval) {
+        retval = db;
+        break;
     }
+    sbrec_datapath_binding_index_destroy_row(dbval);
 
-    hmap_destroy(&lports->by_name);
-    hmap_destroy(&lports->by_key);
+    return retval;
 }
 
-/* Finds and returns the lport with the given 'name', or NULL if no such lport
- * exists. */
+/* Finds and returns the port binding record with tunnel_key equal to the
+ * given 'port_key' and datapath binding matching 'dp_key', or NULL if no
+ * such port binding exists. */
 const struct sbrec_port_binding *
-lport_lookup_by_name(const struct lport_index *lports, const char *name)
+lport_lookup_by_key(struct ovsdb_idl *idl, uint64_t dp_key, uint64_t port_key)
 {
-    const struct lport *lport;
-    HMAP_FOR_EACH_WITH_HASH (lport, name_node, hash_string(name, 0),
-                             &lports->by_name) {
-        if (!strcmp(lport->pb->logical_port, name)) {
-            return lport->pb;
-        }
+    struct sbrec_port_binding *pbval;
+    const struct sbrec_port_binding *pb, *retval = NULL;
+    const struct sbrec_datapath_binding *db;
+
+    /* Lookup datapath corresponding to dp_key. */
+    db = datapath_lookup_by_key(idl, dp_key);
+    if (!db) {
+        return NULL;
     }
-    return NULL;
-}
 
-const struct sbrec_port_binding *
-lport_lookup_by_key(const struct lport_index *lports,
-                    uint32_t dp_key, uint16_t port_key)
-{
-    const struct lport *lport;
-    HMAP_FOR_EACH_WITH_HASH (lport, key_node, hash_int(port_key, dp_key),
-                             &lports->by_key) {
-        if (port_key == lport->pb->tunnel_key
-            && dp_key == lport->pb->datapath->tunnel_key) {
-            return lport->pb;
-        }
+    /* Build key for an indexed lookup. */
+    pbval = sbrec_port_binding_index_init_row(idl, &sbrec_table_port_binding);
+    sbrec_port_binding_index_set_datapath(pbval, db);
+    sbrec_port_binding_index_set_tunnel_key(pbval, port_key);
+
+    /* Find an entry with matching tunnel_key and datapath UUID. Since this
+     * column pair is declared to be an index in the OVN_Southbound schema,
+     * the first match (if any) will be the only match. */
+    SBREC_PORT_BINDING_FOR_EACH_EQUAL (pb, &lport_by_key_cursor, pbval) {
+        retval = pb;
+        break;
     }
-    return NULL;
+    sbrec_port_binding_index_destroy_row(pbval);
+
+    return retval;
 }
 
 /* Finds and returns the logical multicast group with the given 'name' and
@@ -217,4 +211,18 @@ lport_init(struct ovsdb_idl *idl)
     ovsdb_idl_initialize_cursor(idl, &sbrec_table_multicast_group,
                                 "multicast-group-by-dp-name",
                                 &mc_grp_by_dp_name_cursor);
+
+    /* Create cursor to search port binding table by logical port name. */
+    ovsdb_idl_initialize_cursor(idl, &sbrec_table_port_binding,
+                                "lport-by-name",
+                                &lport_by_name_cursor);
+
+    /* Create cursor to search port binding table by logical port tunnel key
+     * and datapath uuid. */
+    ovsdb_idl_initialize_cursor(idl, &sbrec_table_port_binding, "lport-by-key",
+                                &lport_by_key_cursor);
+
+    /* Create cursor to search datapath binding table by tunnel key. */
+    ovsdb_idl_initialize_cursor(idl, &sbrec_table_datapath_binding,
+                                "dpath-by-key", &dpath_by_key_cursor);
 }
diff --git a/ovn/controller/lport.h b/ovn/controller/lport.h
index 4ee19a5..60532c8 100644
--- a/ovn/controller/lport.h
+++ b/ovn/controller/lport.h
@@ -51,25 +51,11 @@ void ldatapath_index_destroy(struct ldatapath_index *);
 const struct ldatapath *ldatapath_lookup_by_key(
     const struct ldatapath_index *, uint32_t dp_key);
 
-/* Logical port index
- * ==================
- *
- * This data structure holds multiple indexes over logical ports, to allow for
- * efficient searching for logical ports by name or number.
- */
-
-struct lport_index {
-    struct hmap by_name;
-    struct hmap by_key;
-};
-
-void lport_index_init(struct lport_index *, struct ovsdb_idl *);
-void lport_index_destroy(struct lport_index *);
 
 const struct sbrec_port_binding *lport_lookup_by_name(
-    const struct lport_index *, const char *name);
+    struct ovsdb_idl *, const char *name);
 const struct sbrec_port_binding *lport_lookup_by_key(
-    const struct lport_index *, uint32_t dp_key, uint16_t port_key);
+    struct ovsdb_idl *, uint64_t dp_key, uint64_t port_key);
 
 
 const struct sbrec_multicast_group *mcgroup_lookup_by_dp_name(
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index e30e83b..4455083 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -537,6 +537,26 @@ create_ovnsb_indexes(struct ovsdb_idl *ovnsb_idl)
                                OVSDB_INDEX_ASC, NULL);
     ovsdb_idl_index_add_column(index, &sbrec_multicast_group_col_datapath,
                                OVSDB_INDEX_ASC, NULL);
+
+    /* Index logical port table by name. */
+    index = ovsdb_idl_create_index(ovnsb_idl, &sbrec_table_port_binding,
+                                   "lport-by-name");
+    ovsdb_idl_index_add_column(index, &sbrec_port_binding_col_logical_port,
+                               OVSDB_INDEX_ASC, NULL);
+
+    /* Index logical port table by tunnel key and datapath. */
+    index = ovsdb_idl_create_index(ovnsb_idl, &sbrec_table_port_binding,
+                                   "lport-by-key");
+    ovsdb_idl_index_add_column(index, &sbrec_port_binding_col_tunnel_key,
+                               OVSDB_INDEX_ASC, NULL);
+    ovsdb_idl_index_add_column(index, &sbrec_port_binding_col_datapath,
+                               OVSDB_INDEX_ASC, NULL);
+
+    /* Index datapath binding table by tunnel key. */
+    index = ovsdb_idl_create_index(ovnsb_idl, &sbrec_table_datapath_binding,
+                                   "dpath-by-key");
+    ovsdb_idl_index_add_column(index, &sbrec_datapath_binding_col_tunnel_key,
+                               OVSDB_INDEX_ASC, NULL);
 }
 
 int
@@ -643,15 +663,13 @@ main(int argc, char *argv[])
         const char *chassis_id = get_chassis_id(ctx.ovs_idl);
 
         struct ldatapath_index ldatapaths;
-        struct lport_index lports;
         ldatapath_index_init(&ldatapaths, ctx.ovnsb_idl);
-        lport_index_init(&lports, ctx.ovnsb_idl);
 
         const struct sbrec_chassis *chassis = NULL;
         if (chassis_id) {
             chassis = chassis_run(&ctx, chassis_id, br_int);
             encaps_run(&ctx, br_int, chassis_id);
-            binding_run(&ctx, br_int, chassis, &ldatapaths, &lports,
+            binding_run(&ctx, br_int, chassis, &ldatapaths,
                         &local_datapaths, &local_lports);
         }
 
@@ -664,7 +682,7 @@ main(int argc, char *argv[])
             enum mf_field_id mff_ovn_geneve = ofctrl_run(br_int,
                                                          &pending_ct_zones);
 
-            pinctrl_run(&ctx, &lports, br_int, chassis, &local_datapaths);
+            pinctrl_run(&ctx, br_int, chassis, &local_datapaths);
             update_ct_zones(&local_lports, &local_datapaths, &ct_zones,
                             ct_zone_bitmap, &pending_ct_zones);
             if (ctx.ovs_idl_txn) {
@@ -672,11 +690,11 @@ main(int argc, char *argv[])
                     commit_ct_zones(br_int, &pending_ct_zones);
 
                     struct hmap flow_table = HMAP_INITIALIZER(&flow_table);
-                    lflow_run(&ctx, chassis, &lports, &local_datapaths,
+                    lflow_run(&ctx, chassis, &local_datapaths,
                               &group_table, &addr_sets, &flow_table);
 
                     physical_run(&ctx, mff_ovn_geneve,
-                                 br_int, chassis, &ct_zones, &lports,
+                                 br_int, chassis, &ct_zones,
                                  &flow_table, &local_datapaths, &local_lports);
 
                     ofctrl_put(&flow_table, &pending_ct_zones,
@@ -721,7 +739,6 @@ main(int argc, char *argv[])
             free(pending_pkt.flow_s);
         }
 
-        lport_index_destroy(&lports);
         ldatapath_index_destroy(&ldatapaths);
 
         sset_destroy(&local_lports);
diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
index f2d9676..8aa3603 100644
--- a/ovn/controller/physical.c
+++ b/ovn/controller/physical.c
@@ -286,9 +286,9 @@ load_logical_ingress_metadata(const struct sbrec_port_binding *binding,
 }
 
 static void
-consider_port_binding(enum mf_field_id mff_ovn_geneve,
+consider_port_binding(struct controller_ctx *ctx,
+                      enum mf_field_id mff_ovn_geneve,
                       const struct simap *ct_zones,
-                      const struct lport_index *lports,
                       struct hmap *local_datapaths,
                       const struct sbrec_port_binding *binding,
                       const struct sbrec_chassis *chassis,
@@ -311,7 +311,7 @@ consider_port_binding(enum mf_field_id mff_ovn_geneve,
         }
 
         const struct sbrec_port_binding *peer = lport_lookup_by_name(
-            lports, peer_name);
+            ctx->ovnsb_idl, peer_name);
         if (!peer || strcmp(peer->type, binding->type)) {
             return;
         }
@@ -373,7 +373,7 @@ consider_port_binding(enum mf_field_id mff_ovn_geneve,
         const char *distributed_port = smap_get_def(&binding->options,
                                                     "distributed-port", "");
         const struct sbrec_port_binding *distributed_binding
-            = lport_lookup_by_name(lports, distributed_port);
+            = lport_lookup_by_name(ctx->ovnsb_idl, distributed_port);
 
         if (!distributed_binding) {
             /* Packet will be dropped. */
@@ -768,7 +768,7 @@ void
 physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve,
              const struct ovsrec_bridge *br_int,
              const struct sbrec_chassis *chassis,
-             const struct simap *ct_zones, struct lport_index *lports,
+             const struct simap *ct_zones,
              struct hmap *flow_table, struct hmap *local_datapaths,
              const struct sset *local_lports)
 {
@@ -890,7 +890,7 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve,
      * 64 for logical-to-physical translation. */
     const struct sbrec_port_binding *binding;
     SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) {
-        consider_port_binding(mff_ovn_geneve, ct_zones, lports,
+        consider_port_binding(ctx, mff_ovn_geneve, ct_zones,
                               local_datapaths, binding, chassis,
                               &ofpacts, flow_table);
     }
@@ -1014,7 +1014,7 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve,
          * rule with higher priority for every localport in this
          * datapath. */
         const struct sbrec_port_binding *pb = lport_lookup_by_name(
-            lports, localport);
+            ctx->ovnsb_idl, localport);
         if (pb && !strcmp(pb->type, "localport")) {
             match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, pb->tunnel_key);
             match_set_metadata(&match, htonll(pb->datapath->tunnel_key));
diff --git a/ovn/controller/physical.h b/ovn/controller/physical.h
index 66aa80e..d70f45b 100644
--- a/ovn/controller/physical.h
+++ b/ovn/controller/physical.h
@@ -45,7 +45,7 @@ void physical_register_ovs_idl(struct ovsdb_idl *);
 void physical_run(struct controller_ctx *, enum mf_field_id mff_ovn_geneve,
                   const struct ovsrec_bridge *br_int,
                   const struct sbrec_chassis *chassis,
-                  const struct simap *ct_zones, struct lport_index *,
+                  const struct simap *ct_zones,
                   struct hmap *flow_table, struct hmap *local_datapaths,
                   const struct sset *local_lports);
 
diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c
index 660233a..e1fb188 100644
--- a/ovn/controller/pinctrl.c
+++ b/ovn/controller/pinctrl.c
@@ -61,17 +61,16 @@ static void pinctrl_handle_put_mac_binding(const struct flow *md,
                                            bool is_arp);
 static void init_put_mac_bindings(void);
 static void destroy_put_mac_bindings(void);
-static void run_put_mac_bindings(struct controller_ctx *,
-                                 const struct lport_index *lports);
+static void run_put_mac_bindings(struct controller_ctx *);
 static void wait_put_mac_bindings(struct controller_ctx *);
 static void flush_put_mac_bindings(void);
 
 static void init_send_garps(void);
 static void destroy_send_garps(void);
 static void send_garp_wait(void);
-static void send_garp_run(const struct ovsrec_bridge *,
+static void send_garp_run(struct controller_ctx *ctx,
+                          const struct ovsrec_bridge *,
                           const struct sbrec_chassis *,
-                          const struct lport_index *lports,
                           struct hmap *local_datapaths);
 static void pinctrl_handle_nd_na(const struct flow *ip_flow,
                                  const struct match *md,
@@ -1013,7 +1012,7 @@ pinctrl_recv(const struct ofp_header *oh, enum ofptype type,
 }
 
 void
-pinctrl_run(struct controller_ctx *ctx, const struct lport_index *lports,
+pinctrl_run(struct controller_ctx *ctx,
             const struct ovsrec_bridge *br_int,
             const struct sbrec_chassis *chassis,
             struct hmap *local_datapaths)
@@ -1050,8 +1049,8 @@ pinctrl_run(struct controller_ctx *ctx, const struct lport_index *lports,
         }
     }
 
-    run_put_mac_bindings(ctx, lports);
-    send_garp_run(br_int, chassis, lports, local_datapaths);
+    run_put_mac_bindings(ctx);
+    send_garp_run(ctx, br_int, chassis, local_datapaths);
 }
 
 void
@@ -1164,7 +1163,6 @@ pinctrl_handle_put_mac_binding(const struct flow *md,
 
 static void
 run_put_mac_binding(struct controller_ctx *ctx,
-                    const struct lport_index *lports,
                     const struct put_mac_binding *pmb)
 {
     if (time_msec() > pmb->timestamp + 1000) {
@@ -1173,7 +1171,7 @@ run_put_mac_binding(struct controller_ctx *ctx,
 
     /* Convert logical datapath and logical port key into lport. */
     const struct sbrec_port_binding *pb
-        = lport_lookup_by_key(lports, pmb->dp_key, pmb->port_key);
+        = lport_lookup_by_key(ctx->ovnsb_idl, pmb->dp_key, pmb->port_key);
     if (!pb) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
@@ -1211,8 +1209,7 @@ run_put_mac_binding(struct controller_ctx *ctx,
 }
 
 static void
-run_put_mac_bindings(struct controller_ctx *ctx,
-                     const struct lport_index *lports)
+run_put_mac_bindings(struct controller_ctx *ctx)
 {
     if (!ctx->ovnsb_idl_txn) {
         return;
@@ -1220,7 +1217,7 @@ run_put_mac_bindings(struct controller_ctx *ctx,
 
     const struct put_mac_binding *pmb;
     HMAP_FOR_EACH (pmb, hmap_node, &put_mac_bindings) {
-        run_put_mac_binding(ctx, lports, pmb);
+        run_put_mac_binding(ctx, pmb);
     }
     flush_put_mac_bindings();
 }
@@ -1413,9 +1410,9 @@ send_garp(struct garp_data *garp, long long int current_time)
 
 /* Get localnet vifs, local l3gw ports and ofport for localnet patch ports. */
 static void
-get_localnet_vifs_l3gwports(const struct ovsrec_bridge *br_int,
+get_localnet_vifs_l3gwports(struct controller_ctx *ctx,
+                  const struct ovsrec_bridge *br_int,
                   const struct sbrec_chassis *chassis,
-                  const struct lport_index *lports,
                   struct hmap *local_datapaths,
                   struct sset *localnet_vifs,
                   struct simap *localnet_ofports,
@@ -1454,7 +1451,7 @@ get_localnet_vifs_l3gwports(const struct ovsrec_bridge *br_int,
                 continue;
             }
             const struct sbrec_port_binding *pb
-                = lport_lookup_by_name(lports, iface_id);
+                = lport_lookup_by_name(ctx->ovnsb_idl, iface_id);
             if (!pb) {
                 continue;
             }
@@ -1488,12 +1485,12 @@ get_localnet_vifs_l3gwports(const struct ovsrec_bridge *br_int,
 }
 
 static bool
-pinctrl_is_chassis_resident(const struct lport_index *lports,
+pinctrl_is_chassis_resident(struct controller_ctx *ctx,
                             const struct sbrec_chassis *chassis,
                             const char *port_name)
 {
     const struct sbrec_port_binding *pb
-        = lport_lookup_by_name(lports, port_name);
+        = lport_lookup_by_name(ctx->ovnsb_idl, port_name);
     return pb && pb->chassis && pb->chassis == chassis;
 }
 
@@ -1564,10 +1561,10 @@ extract_addresses_with_port(const char *addresses,
 }
 
 static void
-consider_nat_address(const char *nat_address,
+consider_nat_address(struct controller_ctx *ctx,
+                     const char *nat_address,
                      const struct sbrec_port_binding *pb,
                      struct sset *nat_address_keys,
-                     const struct lport_index *lports,
                      const struct sbrec_chassis *chassis,
                      struct shash *nat_addresses)
 {
@@ -1575,7 +1572,7 @@ consider_nat_address(const char *nat_address,
     char *lport = NULL;
     if (!extract_addresses_with_port(nat_address, laddrs, &lport)
         || (!lport && !strcmp(pb->type, "patch"))
-        || (lport && !pinctrl_is_chassis_resident(lports, chassis, lport))) {
+        || (lport && !pinctrl_is_chassis_resident(ctx, chassis, lport))) {
         destroy_lport_addresses(laddrs);
         free(laddrs);
         free(lport);
@@ -1594,24 +1591,25 @@ consider_nat_address(const char *nat_address,
 }
 
 static void
-get_nat_addresses_and_keys(struct sset *nat_address_keys,
+get_nat_addresses_and_keys(struct controller_ctx *ctx,
+                           struct sset *nat_address_keys,
                            struct sset *local_l3gw_ports,
-                           const struct lport_index *lports,
                            const struct sbrec_chassis *chassis,
                            struct shash *nat_addresses)
 {
     const char *gw_port;
     SSET_FOR_EACH(gw_port, local_l3gw_ports) {
-        const struct sbrec_port_binding *pb = lport_lookup_by_name(lports,
-                                                                   gw_port);
+        const struct sbrec_port_binding *pb;
+
+        pb = lport_lookup_by_name(ctx->ovnsb_idl, gw_port);
         if (!pb) {
             continue;
         }
 
         if (pb->n_nat_addresses) {
             for (int i = 0; i < pb->n_nat_addresses; i++) {
-                consider_nat_address(pb->nat_addresses[i], pb,
-                                     nat_address_keys, lports, chassis,
+                consider_nat_address(ctx, pb->nat_addresses[i], pb,
+                                     nat_address_keys, chassis,
                                      nat_addresses);
             }
         } else {
@@ -1620,8 +1618,8 @@ get_nat_addresses_and_keys(struct sset *nat_address_keys,
             const char *nat_addresses_options = smap_get(&pb->options,
                                                          "nat-addresses");
             if (nat_addresses_options) {
-                consider_nat_address(nat_addresses_options, pb,
-                                     nat_address_keys, lports, chassis,
+                consider_nat_address(ctx, nat_addresses_options, pb,
+                                     nat_address_keys, chassis,
                                      nat_addresses);
             }
         }
@@ -1635,9 +1633,9 @@ send_garp_wait(void)
 }
 
 static void
-send_garp_run(const struct ovsrec_bridge *br_int,
+send_garp_run(struct controller_ctx *ctx,
+              const struct ovsrec_bridge *br_int,
               const struct sbrec_chassis *chassis,
-              const struct lport_index *lports,
               struct hmap *local_datapaths)
 {
     struct sset localnet_vifs = SSET_INITIALIZER(&localnet_vifs);
@@ -1648,10 +1646,10 @@ send_garp_run(const struct ovsrec_bridge *br_int,
 
     shash_init(&nat_addresses);
 
-    get_localnet_vifs_l3gwports(br_int, chassis, lports, local_datapaths,
+    get_localnet_vifs_l3gwports(ctx, br_int, chassis, local_datapaths,
                       &localnet_vifs, &localnet_ofports, &local_l3gw_ports);
 
-    get_nat_addresses_and_keys(&nat_ip_keys, &local_l3gw_ports, lports,
+    get_nat_addresses_and_keys(ctx, &nat_ip_keys, &local_l3gw_ports,
                                chassis, &nat_addresses);
     /* For deleted ports and deleted nat ips, remove from send_garp_data. */
     struct shash_node *iter, *next;
@@ -1665,8 +1663,9 @@ send_garp_run(const struct ovsrec_bridge *br_int,
     /* Update send_garp_data. */
     const char *iface_id;
     SSET_FOR_EACH (iface_id, &localnet_vifs) {
-        const struct sbrec_port_binding *pb = lport_lookup_by_name(lports,
-                                                                   iface_id);
+        const struct sbrec_port_binding *pb;
+
+        pb = lport_lookup_by_name(ctx->ovnsb_idl, iface_id);
         if (pb) {
             send_garp_update(pb, &localnet_ofports, local_datapaths,
                              &nat_addresses);
@@ -1676,8 +1675,9 @@ send_garp_run(const struct ovsrec_bridge *br_int,
     /* Update send_garp_data for nat-addresses. */
     const char *gw_port;
     SSET_FOR_EACH (gw_port, &local_l3gw_ports) {
-        const struct sbrec_port_binding *pb = lport_lookup_by_name(lports,
-                                                                gw_port);
+        const struct sbrec_port_binding *pb;
+
+        pb = lport_lookup_by_name(ctx->ovnsb_idl, gw_port);
         if (pb) {
             send_garp_update(pb, &localnet_ofports, local_datapaths,
                              &nat_addresses);
diff --git a/ovn/controller/pinctrl.h b/ovn/controller/pinctrl.h
index 230580b..0b7afab 100644
--- a/ovn/controller/pinctrl.h
+++ b/ovn/controller/pinctrl.h
@@ -28,7 +28,7 @@ struct ovsrec_bridge;
 struct sbrec_chassis;
 
 void pinctrl_init(void);
-void pinctrl_run(struct controller_ctx *, const struct lport_index *,
+void pinctrl_run(struct controller_ctx *,
                  const struct ovsrec_bridge *, const struct sbrec_chassis *,
                  struct hmap *local_datapaths);
 void pinctrl_wait(struct controller_ctx *);
